从概念上讲,STRUCT
列包含一个称为“条目”的有序列。这些条目通过字符串名称引用。本文档将这些条目名称称为键。STRUCT
列中的每一行必须具有相同的键。结构条目的名称是模式的一部分。STRUCT
列中的每一行必须具有相同的布局。结构条目的名称不区分大小写。
STRUCT
通常用于将多个列嵌套到一个列中,嵌套的列可以是任何类型,包括其他STRUCT
和LIST
。
STRUCT
s 类似于 PostgreSQL 的 ROW
类型。关键区别在于 DuckDB 的 STRUCT
s 要求在 STRUCT
列的每一行中具有相同的键。这使得 DuckDB 能够通过充分利用其向量化执行引擎显著提高性能,并且还强制类型一致性以提高正确性。DuckDB 包含一个 row
函数作为生成 STRUCT
的特殊方式,但没有 ROW
数据类型。请参阅下面的示例和 STRUCT
函数文档 以获取详细信息。
STRUCT
具有固定的模式。无法使用UPDATE
操作更改STRUCT
的模式。
See the data types overview for a comparison between nested data types.
创建结构体
可以使用struct_pack(name := expr, ...)
函数、等效的数组表示法{'name': expr, ...}
、使用行变量或使用row
函数来创建结构体。
使用struct_pack
函数创建一个结构体。注意键周围没有单引号,并且使用了:=
操作符:
SELECT struct_pack(key1 := 'value1', key2 := 42) AS s;
使用数组表示法创建一个结构体:
SELECT {'key1': 'value1', 'key2': 42} AS s;
使用行变量创建一个结构体:
SELECT d AS s FROM (SELECT 'value1' AS key1, 42 AS key2) d;
创建一个整数结构体:
SELECT {'x': 1, 'y': 2, 'z': 3} AS s;
创建一个带有NULL
值的字符串结构体:
SELECT {'yes': 'duck', 'maybe': 'goose', 'huh': NULL, 'no': 'heron'} AS s;
为每个键创建一个具有不同类型的结构体:
SELECT {'key1': 'string', 'key2': 1, 'key3': 12.345} AS s;
创建一个包含NULL
值的结构体:
SELECT {
'birds': {'yes': 'duck', 'maybe': 'goose', 'huh': NULL, 'no': 'heron'},
'aliens': NULL,
'amphibians': {'yes': 'frog', 'maybe': 'salamander', 'huh': 'dragon', 'no': 'toad'}
} AS s;
向结构体添加字段/值
添加到整数结构体:
SELECT struct_insert({'a': 1, 'b': 2, 'c': 3}, d := 4) AS s;
从结构体中检索
从结构体中检索值可以使用点符号、括号符号或通过结构体函数如struct_extract
来实现。
使用点符号来检索键位置的值。在以下查询中,子查询生成一个结构列 a
,然后我们使用 a.x
进行查询。
SELECT a.x FROM (SELECT {'x': 1, 'y': 2, 'z': 3} AS a);
如果键包含空格,只需将其用双引号括起来("
)。
SELECT a."x space" FROM (SELECT {'x space': 1, 'y': 2, 'z': 3} AS a);
也可以使用括号表示法。请注意,这里使用单引号('
),因为目的是指定特定的字符串键,并且括号内只能使用常量表达式(不能使用表达式):
SELECT a['x space'] FROM (SELECT {'x space': 1, 'y': 2, 'z': 3} AS a);
struct_extract
函数也是等效的。这将返回1:
SELECT struct_extract({'x space': 1, 'y': 2, 'z': 3}, 'x space');
STRUCT.*
与从结构体中检索单个键不同,星号表示法(*
)可用于从结构体中检索所有键作为单独的列。
这在先前的操作创建了未知形状的结构体时特别有用,或者如果查询必须处理任何潜在的结构体键时。
结构体中的所有键可以使用 *
作为单独的列返回:
SELECT a.*
FROM (SELECT {'x': 1, 'y': 2, 'z': 3} AS a);
x | y | z |
---|---|---|
1 | 2 | 3 |
点符号操作顺序
使用点符号引用结构体可能会与引用模式和表产生歧义。通常,DuckDB首先查找列,然后在列中查找结构体键。DuckDB按照以下顺序解析引用,使用第一个匹配项:
无点
SELECT part1
FROM tbl;
part1
是一个列
One Dot
SELECT part1.part2
FROM tbl;
part1
是一个表,part2
是一个列part1
是一个列,part2
是该列的一个属性
两个(或更多)点
SELECT part1.part2.part3
FROM tbl;
part1
是一个模式,part2
是一个表,part3
是一个列part1
是一个表,part2
是一个列,part3
是该列的一个属性part1
是一个列,part2
是该列的一个属性,part3
是该列的另一个属性
任何额外的部分(例如,.part4.part5
,等等)总是被视为属性
使用row
函数创建结构体
row
函数可用于自动将多列转换为单个结构体列。
使用 row
时,键将为空字符串,以便轻松插入到具有结构体列的表中。
然而,列不能使用 row
函数初始化,必须显式命名。
例如,使用 row
函数将值插入到结构体列中:
CREATE TABLE t1 (s STRUCT(v VARCHAR, i INTEGER));
INSERT INTO t1 VALUES (row('a', 42));
SELECT * FROM t1;
表格将包含一个条目:
{'v': a, 'i': 42}
以下产生与上述相同的结果:
CREATE TABLE t1 AS (
SELECT row('a', 42)::STRUCT(v VARCHAR, i INTEGER)
);
使用row
函数初始化结构体列将会失败:
CREATE TABLE t2 AS SELECT row('a');
Invalid Input Error: A table cannot be created from an unnamed struct
在转换结构体时,字段名称必须匹配。因此,以下查询将失败:
SELECT a::STRUCT(y INTEGER) AS b
FROM
(SELECT {'x': 42} AS a);
Mismatch Type Error: Type STRUCT(x INTEGER) does not match with STRUCT(y INTEGER). Cannot cast STRUCTs - element "x" in source struct was not found in target struct
解决这个问题的方法是使用 struct_pack
代替:
SELECT struct_pack(y := a.x) AS b
FROM
(SELECT {'x': 42} AS a);
row
函数可用于返回未命名的结构体。例如:
SELECT row(x, x + 1, y) FROM (SELECT 1 AS x, 'a' AS y) AS s;
这将产生 (1, 2, a)
。
如果在创建结构体时使用多个表达式,row
函数是可选的。以下查询返回的结果与之前的结果相同:
SELECT (x, x + 1, y) AS s FROM (SELECT 1 AS x, 'a' AS y);
Comparison and Ordering
STRUCT
类型可以使用所有的比较运算符进行比较。
这些比较可以用于逻辑表达式中,
例如 WHERE
和 HAVING
子句,并返回BOOLEAN
值。
对于比较,STRUCT
的键具有固定的位置顺序,从左到右。
比较行为与行比较相同,因此,匹配的键必须位于相同的位置。
具体来说,对于任何STRUCT
比较,适用以下规则:
- 相等性。
s1
和s2
是相等的,如果所有对应的值都相等。 - 小于. 对于第一个索引
i
,其中s1.value[i] != s2.value[i]
: 如果s1.value[i] < s2.value[i]
,则s1
小于s2
。
NULL
values are compared following PostgreSQL's semantics.
Lower nesting levels are used for tie-breaking.
Here are some queries returning true
for the comparison.
SELECT {'k1': 2, 'k2': 3} < {'k1': 2, 'k2': 4} AS result;
SELECT {'k1': 'hello'} < {'k1': 'world'} AS result;
These queries return false
.
SELECT {'k2': 4, 'k1': 3} < {'k2': 2, 'k1': 4} AS result;
SELECT {'k1': [4, 3]} < {'k1': [3, 6, 7]} AS result;
These queries return NULL
.
SELECT {'k1': 2, 'k2': 3} < {'k1': 2, 'k2': NULL} AS result;
此查询返回一个Binder Error
,因为键在位置上不匹配。
SELECT {'k1': 2, 'k2': 3} < {'k2': 2, 'k1': 4} AS result;
Binder Error: Cannot compare values of type STRUCT(k1 INTEGER, k2 INTEGER)
and type STRUCT(k2 INTEGER, k1 INTEGER) - an explicit cast is required
Functions
参见 Struct Functions。