这是本节的多页打印视图。
点击此处打印.
返回本页常规视图.
复杂类型
结构(也称为行)、数组和映射等复杂类型由基元类型组成,有时也由其他复杂类型组成。可以通过以下方式使用复杂类型:
MAP 类型是旧类型。要表示映射,请使用 ARRAY[ROW]。
如果 flex 表有一个使用复杂类型的实际列,则该列中的值不包含在 __raw__
列中。有关详细信息,请参阅将数据加载到 Flex 表实际列。
1 - ARRAY
表示数组数据。Vertica 中有两种类型的数组:
两种数组类型的运行方式相同,但它们具有不同的 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],则该集与数组具有相同的二进制大小。
如果从一种元素类型转换为另一种元素类型,则生成的集合使用默认二进制大小。如果这会导致数据不适合,则转换失败。
您不能从数组转换为具有不同维度的数组,例如从二维数组转换为一维数组。
函数和运算符
有关可用于操作数组和集合的函数的完整列表,请参阅 集合函数。
可以通过以下方式使用集合:
集合不能以下列方式使用:
2 - MAP
仅以 Parquet、ORC 和 Avro 格式表示外部表中的映射数据。MAP 只能使用基元类型,而且不能包含其他复杂类型。您可以在表定义中使用 MAP 类型来利用数据中的列,但不能查询这些列。
MAP 的更好替代方法是 ARRAY[ROW]。行数组可以使用所有受支持的复杂类型并且可以查询。这是 INFER_TABLE_DDL 建议的表示。对于 Avro 数据,ROW 必须具有名为 key
和 value
的字段。
在单个表中,您必须使用相同的方法(MAP 或 ARRAY[ROW])定义所有映射列。
语法
在列定义中:
MAP<key,value>
列定义的映射输入格式
在外部表的列定义中,MAP 由指定为类型的键值对组成。以下示例中的表定义了产品 ID 到名称的映射。
=> CREATE EXTERNAL TABLE store (storeID INT, inventory MAP<INT,VARCHAR(100)>)
AS COPY FROM '...' PARQUET;
3 - ROW
表示结构化数据(结构)。ROW 可以包含 Vertica 支持的任何基元类型或复杂类型的字段。
语法
在列定义中:
-
ROW([field] type[, ...])
如果省略字段名称,Vertica 会生成以“f0”开头的名称。
-
在字面量中:
ROW(value [AS field] [, ...]) [AS name(field[, ...])]
列定义的语法
在列定义中,ROW 由一个或多个以逗号分隔的字段名和类型对组成。在以下示例中,Parquet 数据文件包含地址的结构,其在外部表中作为 ROW 读取:
=> CREATE EXTERNAL TABLE customers (name VARCHAR,
address ROW(street VARCHAR, city VARCHAR, zipcode INT))
AS COPY FROM '...' PARQUET;
ROW 可以嵌套;一个字段可以有一个 ROW 类型:
=> CREATE TABLE employees(
employeeID INT,
personal ROW(
name VARCHAR,
address ROW(street VARCHAR, city VARCHAR, zipcode INT),
taxID INT),
department VARCHAR);
ROW 可以包含数组:
=> CREATE TABLE customers(
name VARCHAR,
contact ROW(
street VARCHAR,
city VARCHAR,
zipcode INT,
email ARRAY[VARCHAR]
),
accountid INT );
加载数据时,表定义中的基元类型必须与数据中的基元类型相匹配。ROW 结构也必须匹配;ROW 必须包含且仅包含数据中结构的所有字段。
ROW 列的限制
ROW 列有几个限制:
-
最大嵌套深度为 100。
-
Vertica 表最多支持 9800 个列和字段。不计算 ROW 本身,只计算其字段。
-
ROW 列不能使用任何约束(例如 NOT NULL)或默认值。
-
ROW 字段不能是 auto_increment 或 setof。
-
ROW 定义必须至少包含一个字段。
-
“Row”是 ROW 定义中的保留关键字,但允许作为表或列的名称。
-
不能使用 ALTER TABLE...ALTER COLUMN 修改 ROW 列。
-
包含 ROW 列的表也不能包含标识、自动增量、默认、SET USING 或序列列。
直接构造的语法(字面量)
在字面量中,例如比较操作中的值,ROW 由一个或多个值组成。如果您在 ROW 表达式中省略字段名称,Vertica 会自动生成它们。如果您不强制转换类型,Vertica 会根据数据值推断类型。
=> SELECT ROW('Amy',2,false);
row
--------------------------------------------
{"f0":"Amy","f1":2,"f2":false}
(1 row)
您可以使用 AS 子句来命名 ROW 及其字段:
=> SELECT ROW('Amy',2,false) AS student(name, id, current);
student
--------------------------------------------
{"name":"Amy","id":2,"current":false}
(1 row)
您还可以使用 AS 命名单个字段。此查询产生的输出与之前的输出相同:
=> SELECT ROW('Amy' AS name, 2 AS id, false AS current) AS student;
您无需命名所有字段。
在 ROW 元素数组中,如果您使用 AS 命名字段且元素之间的名称不同,Vertica 会为所有元素使用最右边的名称:
=> SELECT ARRAY[ROW('Amy' AS name, 2 AS id),ROW('Fred' AS first_name, 4 AS id)];
array
------------------------------------------------------------
[{"first_name":"Amy","id":2},{"first_name":"Fred","id":4}]
(1 row)
您可以显式强制转换类型:
=> SELECT ROW('Amy',2.5::int,false::varchar);
row
------------------------------------------
{"f0":"Amy","f1":3,"f2":"f"}
(1 row)
使用单引号转义字面量输入中的单引号,如以下示例所示:
=> SELECT ROW('Howard''s house',2,false);
row
---------------------------------------------------
{"f0":"Howard's house","f1":2,"f2":false}
(1 row)
您可以使用所有标量类型、ROW 和 ARRAY 的字段,如以下示例所示:
=> SELECT id.name, major, GPA FROM students
WHERE id = ROW('alice',119, ARRAY['alice@example.com','ap16@cs.example.edu']);
name | major | GPA
-------+------------------------------------+-----
alice | [{"school":"Science","dept":"CS"}] | 3.8
(1 row)
输出格式
ROW 值以 JSON 格式输出,如以下示例所示。
=> CREATE EXTERNAL TABLE customers (name VARCHAR,
address ROW(street VARCHAR, city VARCHAR, zipcode INT))
AS COPY FROM '...' PARQUET;
=> SELECT address FROM customers WHERE address.city ='Pasadena';
address
--------------------------------------------------------------------
{"street":"100 Main St Apt 4B","city":"Pasadena","zipcode":91001}
{"street":"100 Main St Apt 4A","city":"Pasadena","zipcode":91001}
{"street":"23 Fifth Ave Apt 8C","city":"Pasadena","zipcode":91001}
{"street":"15 Raymond Dr","city":"Pasadena","zipcode":91003}
(4 rows)
下表指定了从 Vertica 数据类型到 JSON 数据类型的映射。
比较
ROW 支持在具有相同字段集的输入之间使用相等 (=
)、不相等 (<>
) 和空安全相等 (<=>
)。仅包含基元类型的 ROW(包括基元类型的嵌套 ROW)也支持比较运算符(<
、<=
、>
、>=
)。
当且仅当所有字段都相等时,两个 ROW 相等。Vertica 按顺序比较字段,直到发现不相等或已比较了所有字段。第一个不相等字段的求值决定哪个 ROW 更大:
=> SELECT ROW(1, 'joe') > ROW(2, 'bob');
?column?
----------
f
(1 row)
具有不同架构的 ROW 之间的比较失败:
=> SELECT ROW(1, 'joe') > ROW(2, 'bob', 123);
ERROR 5162: Unequal number of entries in row expressions
如果比较结果依赖于 null 字段,则结果为 null:
=> select row(1, null, 3) = row(1, 2, 3);
?column?
----------
(1 row)
NULL 处理
如果结构存在但字段值为 null,Vertica 会将 NULL 作为其在 ROW 中的值。所有字段为 null 的结构被视为具有 null 字段的 ROW。如果结构本身为 null,Vertica 会将 ROW 读取为 NULL。
强制转换
转换 ROW 将转换每个字段。因此,您可以按照与标量值转换相同的规则在数据类型之间转换。
以下示例将转换客户表中的 contact
ROW,将 zipcode
字段从 INT 更改为 VARCHAR 并向数组添加边界:
=> SELECT contact::ROW(VARCHAR,VARCHAR,VARCHAR,ARRAY[VARCHAR,20]) FROM customers;
contact
--------------------------------------------------------------------------------
-----------------------------------------
{"street":"911 San Marcos St","city":"Austin","zipcode":"73344","email":["missy@mit.edu","mcooper@cern.gov"]}
{"street":"100 Main St Apt 4B","city":"Pasadena","zipcode":"91001","email":["shelly@meemaw.name","cooper@caltech.edu"]}
{"street":"100 Main St Apt 4A","city":"Pasadena","zipcode":"91001","email":["hofstadter@caltech.edu"]}
{"street":"23 Fifth Ave Apt 8C","city":"Pasadena","zipcode":"91001","email":[]}
{"street":null,"city":"Pasadena","zipcode":"91001","email":["raj@available.com"]}
(6 rows)
您可以指定新字段名称以在输出中更改它们:
=> SELECT contact::ROW(str VARCHAR, city VARCHAR, zip VARCHAR, email ARRAY[VARCHAR,
20]) FROM customers;
contact
--------------------------------------------------------------------------------
----------------------------------
{"str":"911 San Marcos St","city":"Austin","zip":"73344","email":["missy@mit.edu","mcooper@cern.gov"]}
{"str":"100 Main St Apt 4B","city":"Pasadena","zip":"91001","email":["shelly@meemaw.name","cooper@caltech.edu"]}
{"str":"100 Main St Apt 4A","city":"Pasadena","zip":"91001","email":["hofstadter@caltech.edu"]}
{"str":"23 Fifth Ave Apt 8C","city":"Pasadena","zip":"91001","email":[]}
{"str":null,"city":"Pasadena","zip":"91001","email":["raj@available.com"]}
(6 rows)
支持的运算符和谓词
可以通过以下方式在查询中使用 ROW 值:
ROW 值不支持以下运算符和谓词:
-
数学运算符
-
整行类型强制转换(支持字段值强制转换)
-
BITWISE、LIKE
-
MLA (ROLLUP, CUBE, GROUPING SETS)
-
聚合函数,包括 MAX、MIN 和 SUM
-
集运算符,包括 UNION、UNION ALL、MINUS 和 INTERSECT
从用户定义的标量函数返回的 ROW 不支持 COUNT,但 ROW 列和字面量支持 COUNT。
在比较操作(包括 ORDER BY 之类的隐式比较)中,ROW 字面量被视为其字段值的序列。例如,以下两个语句是等效的:
GROUP BY ROW(zipcode, city)
GROUP BY zipcode, city
在视图和子查询中使用行
您可以使用 ROW 列来构造视图和子查询。考虑具有以下定义的员工和客户表:
=> CREATE EXTERNAL TABLE customers(name VARCHAR,
address ROW(street VARCHAR, city VARCHAR, zipcode INT), accountID INT)
AS COPY FROM '...' PARQUET;
=> CREATE EXTERNAL TABLE employees(employeeID INT,
personal ROW(name VARCHAR,
address ROW(street VARCHAR, city VARCHAR, zipcode INT),
taxID INT), department VARCHAR)
AS COPY FROM '...' PARQUET;
以下示例将创建一个视图并对其进行查询。
=> CREATE VIEW neighbors (num_neighbors, area(city, zipcode))
AS SELECT count(*), ROW(address.city, address.zipcode)
FROM customers GROUP BY address.city, address.zipcode;
CREATE VIEW
=> SELECT employees.personal.name, neighbors.area FROM neighbors, employees
WHERE employees.personal.address.zipcode=neighbors.area.zipcode AND neighbors.nu
m_neighbors > 1;
name | area
--------------------+-------------------------------------
Sheldon Cooper | {"city":"Pasadena","zipcode":91001}
Leonard Hofstadter | {"city":"Pasadena","zipcode":91001}
(2 rows)
4 - SET
表示无序的、唯一元素的集合。集可能只包含基元类型。与数组不同,在集中,元素位置是没有意义的。
集不支持 LONG 类型(如 LONG VARBINARY 或 LONG VARCHAR)或用户定义类型(如 Geometry)。
如果您从数组填充集,Vertica 会对值进行排序并移除重复元素。如果您不关心元素位置并计划运行检查特定元素是否存在的查询(查找、包含),则使用集可以提高查询性能。
集可以是有界的(这意味着它们指定了最大元素计数),也可以是无界的。无界集具有最大二进制大小,可以显式设置或默认设置。请参阅元素计数和集合大小的限制。
语法
在列定义中:
SET[data_type, max_elements] |
SET[data_type](max_size) |
SET[data_type]
在字面量中:
SET[value[, ...] ]
限制
-
集仅支持基元类型的数据,例如 int、UUID 等。
-
如果指定了边界,则会对加载或更改数据的所有操作强制执行边界。无界集可以具有适合所分配的二进制大小的任意数量的元素。
-
集具有最大二进制大小。如果在定义集时未设置此大小,则使用默认值。
列定义的语法
列定义中使用的集可以是有界或无界的。有界集必须指定最大元素数。无界集可以指定集的最大二进制大小,也可以使用 DefaultArrayBinarySize 的值。您可以指定边界或二进制大小,但不能同时指定两者。有关这些值的更多信息,请参阅元素计数和集合大小限制。
以下示例定义了一个具有无界集列的表。
=> CREATE TABLE users
(
user_id INTEGER,
display_name VARCHAR,
email_addrs SET[VARCHAR]
);
当您将数组数据加载到定义为集的列中时,数组数据会自动转换为集。
直接构造的语法(字面量)
使用 SET 关键字构造集值。字面量设置值包含在括号中。例如,要创建一个 INT 集,您将执行以下操作:
=> SELECT SET[1,2,3];
set
-------
[1,2,3]
(1 row)
您可以通过转换将数组显式转换为集,如以下示例所示:
=> SELECT ARRAY[1, 5, 2, 6, 3, 0, 6, 4]::SET[INT];
set
-----------------
[0,1,2,3,4,5,6]
(1 row)
请注意,重复元素已移除并且元素已排序。
因为在直接构造集时元素是已知的,所以这些集是隐式有界的。
输出格式
集以类似 JSON 的格式显示,括号中包含逗号分隔的元素(如数组)。在以下示例中,email_addrs 列是一个集。
=> SELECT custkey,email_addrs FROM customers LIMIT 4;
custkey | email_addrs
---------+------------------------------------------------------------------------
342176 | ["joe.smith@example.com"]
342799 | ["bob@example,com","robert.jones@example.com"]
342845 | ["br92@cs.example.edu"]
342321 | ["789123@example-isp.com","sjohnson@eng.example.com","sara@johnson.example.name"]
元素计数和集合大小的限制
在为表列声明集合类型时,您可以限制元素的数量或集合的总二进制大小。在查询处理期间,Vertica 始终根据元素计数或二进制大小保留列所需的最大内存。如果此大小比您的数据实际需要的大得多,则设置这些限制之一可以通过减少必须为列保留的内存量来提高查询性能。
您可以通过强制转换来更改集合的边界,包括在有界和无界集合之间进行更改。请参阅 强制转换。
有界集合指定最大元素计数。有界集合列中的值可能包含较少的元素,但可能不会包含更多。任何将比声明的最大值更多的元素插入有界集合的尝试都是错误的。有界集合的二进制大小是数据类型大小和最大元素数的乘积,可能向上取整。
无界集合显式或隐式指定二进制大小(以字节为单位)。它可能包含尽可能多的元素,以适应该二进制大小。
您可以为无界集合指定最大二进制大小,而不是指定边界。无论集合包含多少元素,二进制大小都是绝对限制。未指定最大二进制大小的集合使用 DefaultArrayBinarySize 的值。此大小在定义集合时设置,不受以后对 DefaultArrayBinarySize 值的更改的影响。
您不能为有界集合设置最大二进制大小,只能设置无界集合。
比较
所有集合都支持相等 (=
)、不等 (<>
) 和 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 SET['1','2','3']::SET[INT];
set
---------
[1,2,3]
(1 row)
=> CREATE TABLE transactions (tid INT, prod_ids SET[VARCHAR], quantities SET[VARCHAR(32)]);
=> INSERT INTO transactions VALUES (12345, SET['p1265', 'p4515'], SET['15','2']);
=> SELECT quantities :: SET[INT] FROM transactions;
quantities
------------
[15,2]
(1 row)
赋值转换和隐式转换的工作方式与标量相同。
您可以在 ARRAY 和 SET 类型之间执行显式转换,但不能执行隐式转换。如果集合是无界的且数据类型未更改,则保留二进制大小。例如,如果将 ARRAY[INT] 转换为 SET[INT],则该集与数组具有相同的二进制大小。
在将数组转换为集时,Vertica 会首先转换每个元素,然后对集进行排序并移除重复项。如果将两个源值转换为相同的目标值,则其中一个将被移除。例如,如果您将 FLOAT 数组转换为一组 INT,则数组中的两个值可能会四舍五入为相同的整数,然后被视为重复项。如果数组包含多个转换为 NULL 的值,也会发生这种情况。
如果从一种元素类型转换为另一种元素类型,则生成的集合使用默认二进制大小。如果这会导致数据不适合,则转换失败。
函数和运算符
有关可用于操作数组和集合的函数的完整列表,请参阅 集合函数。
可以通过以下方式使用集合:
集合不能以下列方式使用: