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 值:
-
INNER 和 OUTER JOIN
-
比较,IN、BETWEEN(仅限不可为空的筛选器)
-
IS NULL、IS NOT NULL
-
CASE
-
GROUP BY、ORDER BY
-
SELECT DISTINCT
-
用户定义的标量、变换和分析函数的实参
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)