ARRAY
表示数组数据。Vertica 中有两种类型的数组:
-
原生数组:基元类型的一维数组。原生数组在 TYPES 系统表中跟踪并在原生表中使用。
-
非原生数组:所有其他受支持的数组,包括包含其他数组(多维数组)或结构 (ROW) 的数组。非原生数组的使用有一些限制。非原生数组在 COMPLEX_TYPES 系统表中跟踪。
两种数组类型的运行方式相同,但它们具有不同的 OID。
数组可以是有界的,这意味着它们指定了最大元素计数,也可以是无界的。无界数组具有最大二进制大小,可以显式设置或默认设置。请参阅元素计数和集合大小的限制。
选定的解析器支持使用 COPY 加载数组。有关详细信息,请参阅各个解析器的文档。
语法
在列定义中:
ARRAY[data_type, max_elements] |
ARRAY[data_type](max_size) |
ARRAY[data_type]
在字面量中:
ARRAY[value[, ...] ]
限制
-
原生数组仅支持原始类型的数据,例如 int、UUID 等。
-
强制执行数组维数。列不能包含不同维度的数组。例如,包含三维数组的列只能包含其他三维数组;它不能同时包含一个一维数组。但是,一列中的数组大小可能不同,其中一个数组可以包含四个元素,而另一个数组包含十个元素。
-
如果指定了数组边界,则对所有加载或更改数据的操作强制执行。无界数组可能包含与分配的二进制大小一样多的元素。
-
数组具有最大二进制大小。如果在定义数组时未设置此大小,则使用默认值。
-
数组不支持 LONG 类型(如 LONG VARBINARY 或 LONG VARCHAR)或用户定义类型(如 Geometry)。
列定义的语法
列定义中使用的数组可以是有界或无界的。有界数组必须指定最大元素数。无界数组可以指定数组的最大二进制大小(以字节为单位),或者使用 DefaultArrayBinarySize 的值。您可以指定边界或二进制大小,但不能同时指定两者。有关这些值的更多信息,请参阅元素计数和集合大小限制。
以下示例使用无界数组为客户定义了一个表:
=> CREATE TABLE customers (id INT, name VARCHAR, email ARRAY[VARCHAR(50)]);
以下示例对客户电子邮件地址使用有界数组,对订单历史记录使用无界数组:
=> CREATE TABLE customers (id INT, name VARCHAR, email ARRAY[VARCHAR(50),5], orders ARRAY[INT]);
以下示例使用具有 ROW 元素的数组:
=> CREATE TABLE orders(
orderid INT,
accountid INT,
shipments ARRAY[
ROW(
shipid INT,
address ROW(
street VARCHAR,
city VARCHAR,
zip INT
),
shipdate DATE
)
]
);
要声明多维数组,请使用嵌套。例如,ARRAY[ARRAY[int]] 指定一个二维数组。
直接构造的语法(字面量)
使用 ARRAY 关键字构造数组值。下面的示例创建一个整数值数组。
=> SELECT ARRAY[1,2,3];
array
-------
[1,2,3]
(1 row)
您可以将一个数组嵌套在另一个数组中,如下例所示。
=> SELECT ARRAY[ARRAY[1],ARRAY[2]];
array
-----------
[[1],[2]]
(1 row)
如果一系列数组不包含 null 元素且无函数调用,则可以缩写语法:
=> SELECT ARRAY[[1,2],[3,4]];
array
---------------
[[1,2],[3,4]]
(1 row)
---not valid:
=> SELECT ARRAY[[1,2],null,[3,4]];
ERROR 4856: Syntax error at or near "null" at character 20
LINE 1: SELECT ARRAY[[1,2],null,[3,4]];
^
数组字面量可以包含所有标量类型(ROW 和 ARRAY)的元素。ROW 元素必须都具有相同的字段集:
=> SELECT ARRAY[ROW(1,2),ROW(1,3)];
array
-----------------------------------
[{"f0":1,"f1":2},{"f0":1,"f1":3}]
(1 row)
=> SELECT ARRAY[ROW(1,2),ROW(1,3,'abc')];
ERROR 3429: For 'ARRAY', types ROW(int,int) and ROW(int,int,unknown) are inconsistent
因为在直接构造数组时元素是已知的,所以这些数组是隐式有界的。
您可以在比较中使用 ARRAY 字面量,如下例所示:
=> SELECT id.name, id.num, GPA FROM students
WHERE major = ARRAY[ROW('Science','Physics')];
name | num | GPA
-------+-----+-----
bob | 121 | 3.3
carol | 123 | 3.4
(2 rows)
输出格式
数组列的查询返回 JSON 格式,值显示在括号中的逗号分隔列表中。以下示例显示了一个包含数组列的查询。
=> SELECT cust_custkey,cust_custstaddress,cust_custcity,cust_custstate from cust;
cust_custkey | cust_custstaddress | cust_custcity | cust_custstate
-------------+------- ----------------------------------------------+---------------------------------------------+----------------
342176 | ["668 SW New Lane","518 Main Ave","7040 Campfire Dr"] | ["Winchester","New Hyde Park","Massapequa"] | ["VA","NY","NY"]
342799 | ["2400 Hearst Avenue","3 Cypress Street"] | ["Berkeley","San Antonio"] | ["CA","TX"]
342845 | ["336 Boylston Street","180 Clarkhill Rd"] | ["Boston","Amherst"] | ["MA","MA"]
342321 | ["95 Fawn Drive"] | ["Allen Park"] | ["MI"]
342989 | ["5 Thompson St"] | ["Massillon"] | ["OH"]
(5 rows)
请注意,JSON 格式转义的一些字符在原生 VARCHAR 中不会转义。例如,如果您将 "c:\users\data"
插入到数组中,则该值的 JSON 输出为 "c:\\\users\\\data"
。
元素访问
数组是从 0 开始索引的。第一个元素的序号位置为 0,第二个元素的序号位置为 1,依此类推。
您可以通过索引访问(取消引用)数组中的元素:
=> SELECT (ARRAY['a','b','c','d','e'])[1];
array
-------
b
(1 row)
要指定范围,请使用格式 start:end。不包括范围的结尾。
=> SELECT(ARRAY['a','b','c','d','e','f','g'])[1:4];
array
---------
["b","c","d"]
(1 row)
要从多维数组中取消引用某个元素,请将每个索引放在括号中:
=> SELECT(ARRAY[ARRAY[1,2],ARRAY[3,4]])[0][0];
array
-------
1
(1 row)
超过边界的索引引用会返回 NULL。
元素计数和集合大小的限制
在为表列声明集合类型时,您可以限制元素的数量或集合的总二进制大小。在查询处理期间,Vertica 始终根据元素计数或二进制大小保留列所需的最大内存。如果此大小比您的数据实际需要的大得多,则设置这些限制之一可以通过减少必须为列保留的内存量来提高查询性能。
您可以通过强制转换来更改集合的边界,包括在有界和无界集合之间进行更改。请参阅 强制转换。
有界集合指定最大元素计数。有界集合列中的值可能包含较少的元素,但可能不会包含更多。任何将比声明的最大值更多的元素插入有界集合的尝试都是错误的。有界集合的二进制大小是数据类型大小和最大元素数的乘积,可能向上取整。
无界集合显式或隐式指定二进制大小(以字节为单位)。它可能包含尽可能多的元素,以适应该二进制大小。
如果嵌套数组为所有维度指定边界,Vertica 会设置一个边界,该边界是这些边界的乘积。在以下示例中,内部和外部数组的边界均为 10,但仅强制执行总元素计数 100。
ARRAY[ARRAY[INT,10],10]
如果嵌套数组仅指定外部集合的边界,则将其视为总边界。上一示例等效于以下示例:
ARRAY[ARRAY[INT],100]
您必须为所有嵌套集合指定边界或仅为外部集合指定边界。对于任何其他边界分布,Vertica 会将集合视为无界。
您可以为无界集合指定最大二进制大小,而不是指定边界。无论集合包含多少元素,二进制大小都是绝对限制。未指定最大二进制大小的集合使用 DefaultArrayBinarySize 的值。此大小在定义集合时设置,不受以后对 DefaultArrayBinarySize 值的更改的影响。
您不能为有界集合设置最大二进制大小,只能设置无界集合。
您可以使用 ALTER TABLE 更改数组列的边界或二进制大小,如下例所示:
=> ALTER TABLE cust ALTER COLUMN orders SET DATA TYPE ARRAY[INTEGER](100);
如果更改减少了集合的大小并导致数据丢失,则更改将失败。
比较
所有集合都支持相等 (=
)、不等 (<>
) 和 null 安全相等 (<=>
)。一维集合还支持以下集合之间的比较运算符 (<
、<=
、>
、>=
) 相同的类型(数组或集合)。比较遵循以下规则:
-
空集合最后排序。
-
使用元素数据类型的排序规则逐个元素比较非空集合。第一对不相等元素的相对顺序决定了两个集合的顺序。
-
如果两个集合中的所有元素都等于较短集合的长度,则较短集合在较长集合之前排序。
-
如果两个集合中的所有元素相等且集合的长度相等,则集合相等。
NULL 处理
集合的空语义在大多数方面与普通列一致。有关空处理的更多信息,请参阅 NULL 排序顺序。
当集合为 null 而不是空时,空安全相等运算符 (<=>) 的行为与相等 (=) 不同。将集合严格地与 NULL 进行比较是未定义的。
=> SELECT ARRAY[1,3] = NULL;
?column?
----------
(1 row)
=> SELECT ARRAY[1,3] <=> NULL;
?column?
----------
f
(1 row)
在以下示例中,表中的授予列对于员工 99 为 null。
=> SELECT grants = NULL FROM employees WHERE id=99;
?column?
----------
(1 row)
=> SELECT grants <=> NULL FROM employees WHERE id=99;
?column?
----------
t
(1 row)
空集合不为 null 并且按预期运行。
=> SELECT ARRAY[]::ARRAY[INT] = ARRAY[]::ARRAY[INT];
?column?
----------
t
(1 row)
集合逐个元素进行比较。如果比较依赖于 null 元素,则结果是未知的 (null),而不是 false。例如,ARRAY[1,2,null]=ARRAY[1,2,null]
和 ARRAY[1,2,null]=ARRAY[1,2,3]
都返回 null,但 ARRAY[1,2,null]=ARRAY[1,4,null]
因为第二个元素不匹配而返回 false。
强制转换
转换一个数组会转换数组的每个元素。因此,您可以按照与标量值转换相同的规则在数据类型之间转换。
您可以显式地转换字面量数组和数组列:
=> SELECT ARRAY['1','2','3']::ARRAY[INT];
array
---------
[1,2,3]
(1 row)
您可以通过强制转换来更改数组或集的边界。当强制转换为有界原生数组时,会截断太长的输入。当转换为非原生数组(包含复杂数据类型(包括其他数组)的数组)时,如果新边界对于数据而言太小,则转换失败:
=> SELECT ARRAY[1,2,3]::ARRAY[VARCHAR,2];
array
-----------
["1","2"]
(1 row)
=> SELECT ARRAY[ARRAY[1,2,3],ARRAY[4,5,6]]::ARRAY[ARRAY[VARCHAR,2],2];
ERROR 9227: Output array isn't big enough
DETAIL: Type limit is 4 elements, but value has 6 elements
如果转换为有界多维数组,则必须在所有级别指定边界:
=> SELECT ARRAY[ARRAY[1,2,3],ARRAY[4,5,6]]::ARRAY[ARRAY[VARCHAR,5],10];
array
-------------------------------
[["1","2","3"],["4","5","6"]]
(1 row)
=> SELECT ARRAY[ARRAY[1,2,3],ARRAY[4,5,6]]::ARRAY[ARRAY[VARCHAR,2]];
WARNING 9753: Collection type bound will not be used
DETAIL: A bound was provided for an inner dimension, but not for an outer dimension
array
-------------------------------
[["1","2","3"],["4","5","6"]]
(1 row)
赋值转换和隐式转换的工作方式与标量相同:
=> CREATE TABLE transactions (tid INT, prod_ids ARRAY[VARCHAR,100], quantities ARRAY[INT,100]);
CREATE TABLE
=> INSERT INTO transactions VALUES (12345, ARRAY['p1265', 'p4515'], ARRAY[15,2]);
OUTPUT
--------
1
(1 row)
=> CREATE TABLE txreport (prod_ids ARRAY[VARCHAR(12),100], quants ARRAY[VARCHAR(32),100]);
CREATE TABLE
=> INSERT INTO txreport SELECT prod_ids, quantities FROM transactions;
OUTPUT
--------
1
(1 row)
=> SELECT * FROM txreport;
prod_ids | quants
-------------------+------------
["p1265","p4515"] | ["15","2"]
(1 row)
您可以在 ARRAY 和 SET 类型(仅限原生数组)之间执行显式转换,但不能执行隐式转换。如果集合是无界的且数据类型未更改,则保留二进制大小。例如,如果将 ARRAY[INT] 转换为 SET[INT],则该集与数组具有相同的二进制大小。
如果从一种元素类型转换为另一种元素类型,则生成的集合使用默认二进制大小。如果这会导致数据不适合,则转换失败。
您不能从数组转换为具有不同维度的数组,例如从二维数组转换为一维数组。
函数和运算符
有关可用于操作数组和集合的函数的完整列表,请参阅 集合函数。
可以通过以下方式使用集合:
-
作为 GROUP BY 子句 中的分组列。
-
仅对于原生数组,作为查询中的 ORDER BY 子句、OVER 子句(请参阅 窗口分区)或 CREATE PROJECTION 语句中的排序键。
-
作为 OVER 子句的 PARTITION BY 部分中的排序键。
-
作为 JOIN 键(请参阅 Joined-table)。
-
CASE 表达式 中的。
集合不能以下列方式使用:
-
作为 IN 或 NOT IN 表达式的一部分。
-
创建表时作为分区列。
-
使用 ANALYZE_STATISTICS 或 TopK 预测。
-
仅限非原生数组:ORDER BY、PARTITION BY、DEFAULT、SET USING 或约束。