结构化数据类型¶
Snowflake 结构化类型有 ARRAY、OBJECT 和 MAP。结构化类型包含具有特定 Snowflake 数据类型 的元素或键值对。
INTEGER 元素的 ARRAY。
包含 VARCHAR 和 NUMBER 键值对的 OBJECT。
将 VARCHAR 键与 DOUBLE 值关联的 MAP。
您可以通过以下方式使用结构化类型:
您可以在 Apache Iceberg™ 表 中定义结构化类型列。
Apache Iceberg™ 数据类型
list
、struct
和map
与 Snowflake 中的结构化 ARRAY、结构化 OBJECT 和 MAP 类型对应。结构化类型列最多支持 1000 个子列。
从 Iceberg 表中的结构化类型列访问数据时,您可以使用结构化类型。
您可以将半结构化 ARRAY、OBJECT 或 VARIANT 值转换为相应的结构化类型(例如,将 ARRAY 值转换为 INTEGER 元素的 ARRAY 值)。您还可以将结构化类型转换为半结构化类型。
备注
目前,Iceberg 表以外的表不支持结构化类型。不能将结构化类型的列添加到常规表中。
本主题介绍如何在 Snowflake 中使用结构化类型。
指定结构化类型¶
定义结构化类型列或将值转换为结构化类型时,请使用以下各部分中所述的语法:
指定结构化 ARRAY 类型¶
若要指定结构化 ARRAY 类型,请使用以下语法:
ARRAY( <element_type> [ NOT NULL ] )
其中:
element_type
是此 ARRAY 中元素的 Snowflake 数据类型。您还可以指定结构的 ARRAY、结构化 OBJECT 或 MAP 作为元素的类型。
备注
在 Iceberg 表列的定义中,不能指定 VARIANT、半结构化 ARRAY 或半结构化 OBJECT 作为 ARRAY 元素类型。
NOT NULL 指定 ARRAY 中不能包含任何的 NULL 元素。
例如,在以下语句中比较 SYSTEM$TYPEOF 函数返回的类型:
第一列的表达式将半结构化 ARRAY 值转换为结构化 ARRAY 值(NUMBER 元素的 ARRAY)。
第二列表达式指定半结构化 ARRAY 值。
SELECT
SYSTEM$TYPEOF(
[1, 2, 3]::ARRAY(NUMBER)
) AS structured_array,
SYSTEM$TYPEOF(
[1, 2, 3]
) AS semi_structured_array;
+-------------------------------+-----------------------+
| STRUCTURED_ARRAY | SEMI_STRUCTURED_ARRAY |
|-------------------------------+-----------------------|
| ARRAY(NUMBER(38,0))[LOB] | ARRAY[LOB] |
+-------------------------------+-----------------------+
指定结构化 OBJECT 类型¶
若要指定结构化 OBJECT 类型,请使用以下语法:
OBJECT(
[
<key> <value_type> [ NOT NULL ]
[ , <key> <value_type> [ NOT NULL ] ]
[ , ... ]
]
)
其中:
key
指定 OBJECT 类型的键。OBJECT 定义中的每个
key
都必须是唯一的。键的顺序是 OBJECT 定义的一部分。不允许以不同顺序比较具有相同键的两个 OBJECT 值。(发生编译时错误。)
如果不指定任何键,但指定括号(即,如果使用
OBJECT()
),生成的类型则是不包含键的结构化 OBJECT。没有键的结构化 OBJECT 与半结构化 OBJECT 不同。
value_type
是键所对应值的 Snowflake 数据类型。您还可以指定结构化 ARRAY、结构化 OBJECT 或 MAP 作为值的类型。
备注
在 Iceberg 表列的定义中,不能指定 VARIANT、半结构化 ARRAY 或半结构化 OBJECT 作为与 OBJECT 键对应的值的类型。
NOT NULL 指定与键对应的值不能为 NULL。
例如,在以下语句中比较 SYSTEM$TYPEOF 函数返回的类型:
第一列表达式将半结构化 OBJECT 值转换为包含以下键和值的结构化 OBJECT 值:
名为
str
的键,且附带非 NULL 的 VARCHAR 值。名为
num
的键,且附带 NUMBER 值。
第二列表达式指定半结构化 OBJECT 值。
SELECT
SYSTEM$TYPEOF(
{
'str': 'test',
'num': 1
}::OBJECT(
str VARCHAR NOT NULL,
num NUMBER
)
) AS structured_object,
SYSTEM$TYPEOF(
{
'str': 'test',
'num': 1
}
) AS semi_structured_object;
+---------------------------------------------------------------+------------------------+
| STRUCTURED_OBJECT | SEMI_STRUCTURED_OBJECT |
|---------------------------------------------------------------+------------------------|
| OBJECT(str VARCHAR(16777216) NOT NULL, num NUMBER(38,0))[LOB] | OBJECT[LOB] |
+---------------------------------------------------------------+------------------------+
指定 MAP 类型¶
若要指定 MAP 类型,请使用以下语法:
MAP( <key_type> , <value_type> [ NOT NULL ] )
其中:
key_type
是用于映射的键的 Snowflake 数据类型。您必须为键使用以下类型之一:VARCHAR
(NUMBER 标度为 0)
不能使用浮点数据类型作为键的类型。
映射键不能是 NULL。
value_type
是映射中值的 Snowflake 数据类型。您还可以指定结构化 ARRAY、结构化 OBJECT 或 MAP 作为值的类型。
备注
在 Iceberg 表列的定义中,不能指定 VARIANT、半结构化 ARRAY 或半结构化 OBJECT 作为 MAP 中值的类型。
NOT NULL 指定与键对应的值不能为 NULL。
下面的示例将半结构化 OBJECT 值转换为 MAP 值,并使用 SYSTEM$TYPEOF 函数打印值的结果类型。MAP 将 VARCHAR 键与 VARCHAR 值关联起来。
SELECT
SYSTEM$TYPEOF(
{
'a_key': 'a_val',
'b_key': 'b_val'
}::MAP(VARCHAR, VARCHAR)
) AS map_example;
+------------------------------------------------+
| MAP_EXAMPLE |
|------------------------------------------------|
| MAP(VARCHAR(16777216), VARCHAR(16777216))[LOB] |
+------------------------------------------------+
在半结构化类型中使用结构化类型¶
不能在 VARIANT、半结构化 OBJECT 或半结构化 ARRAY 值中使用 MAP、结构化 OBJECT 或结构化 ARRAY 值。在以下情况下会发生错误:
转换结构化类型和半结构化类型¶
下表总结了将结构化 OBJECT、结构化 ARRAY 和 MAP 值 转换 为半结构化 OBJECT、ARRAY 和 VARIANT 值的规则(反之亦然)。
源数据类型 |
目标数据类型 |
||
---|---|---|---|
半结构化 ARRAY |
结构化 ARRAY |
✔ |
❌ |
半结构化 OBJECT |
|
✔ |
❌ |
半结构化 VARIANT |
|
✔ |
❌ |
结构化 ARRAY |
半结构化 ARRAY |
✔ |
❌ |
|
半结构化 OBJECT |
✔ |
❌ |
|
半结构化 VARIANT |
✔ |
❌ |
以下各部分将更详细地说明这些规则。
将半结构化类型显式转换为结构化类型¶
要将半结构化类型的值显式转换为结构化类型的值,您可以 调用 CAST 函数或使用 :: 运算符。
备注
结构化类型不支持 TRY_CAST。
您只能将以下半结构化类型的值转换为相应的结构化类型的值;否则,将发生运行时错误。
半结构化类型 |
可转换为的结构化类型 |
---|---|
ARRAY |
结构化 ARRAY |
OBJECT |
MAP 或结构化 OBJECT |
VARIANT |
MAP 或者结构化 ARRAY 或 OBJECT |
接下来的部分将更详细地说明如何转换类型:
将半结构化 ARRAY 和 VARIANT 值转换为结构化 ARRAY 值¶
以下步骤演示了如何将半结构化 ARRAY 或 VARIANT 值转换为 NUMBER 元素的 ARRAY 值:
SELECT
SYSTEM$TYPEOF(
CAST ([1,2,3] AS ARRAY(NUMBER))
) AS array_cast_type,
SYSTEM$TYPEOF(
CAST ([1,2,3]::VARIANT AS ARRAY(NUMBER))
) AS variant_cast_type;
或者:
SELECT
SYSTEM$TYPEOF(
[1,2,3]::ARRAY(NUMBER)
) AS array_cast_type,
SYSTEM$TYPEOF(
[1,2,3]::VARIANT::ARRAY(NUMBER)
) AS variant_cast_type;
+--------------------------+--------------------------+
| ARRAY_CAST_TYPE | VARIANT_CAST_TYPE |
|--------------------------+--------------------------|
| ARRAY(NUMBER(38,0))[LOB] | ARRAY(NUMBER(38,0))[LOB] |
+--------------------------+--------------------------+
当您将半结构化 ARRAY 或 VARIANT 值转换为结构化 ARRAY 值时,请注意以下事项:
ARRAY 值的每个元素都将转换为 ARRAY 的指定类型。
将 ARRAY 列转换为 ARRAY(VARCHAR) 会将每个值转换为 VARCHAR 值:
SELECT CAST ([1,2,3] AS ARRAY(VARCHAR)) AS varchar_array, SYSTEM$TYPEOF(varchar_array) AS array_cast_type;
+---------------+-------------------------------+ | VARCHAR_ARRAY | ARRAY_CAST_TYPE | |---------------+-------------------------------| | [ | ARRAY(VARCHAR(16777216))[LOB] | | "1", | | | "2", | | | "3" | | | ] | | +---------------+-------------------------------+
如果无法将元素转换为指定类型(例如,将
['a', 'b', 'c']
转换为 ARRAY(NUMBER)),则转换失败。如果 ARRAY 值包含 NULL 元素且 ARRAY 类型指定 NOT NULL(例如,将
[1, NULL, 3]
转换为 ARRAY(NUMBER NOT NULL)),则转换失败。如果目标元素类型不支持 JSON 空值(即目标类型不是半结构化 ARRAY、OBJECT 或 VARIANT),则为 JSON 空值 的元素将被转换为 NULL。
例如,如果要转换为 ARRAY(NUMBER),则 JSON 空值将转换为 NULL,因为 NUMBER 不支持 JSON 空值。
另一方面,如果要转换为 ARRAY(VARIANT),则不会将 JSON 空值转换为 NULL,因为 VARIANT 支持 JSON 空值。
将半结构化 OBJECT 和 VARIANT 值转换为结构化 OBJECT 值¶
以下步骤演示如何将半结构化 OBJECT 或 VARIANT 值转换为包含 city
和 state
键值对(即 VARCHAR 值)的结构化 OBJECT 值:
SELECT
SYSTEM$TYPEOF(
CAST ({'city':'San Mateo','state':'CA'} AS OBJECT(city VARCHAR, state VARCHAR))
) AS object_cast_type,
SYSTEM$TYPEOF(
CAST ({'city':'San Mateo','state':'CA'}::VARIANT AS OBJECT(city VARCHAR, state VARCHAR))
) AS variant_cast_type;
或者:
SELECT
SYSTEM$TYPEOF(
{'city':'San Mateo','state':'CA'}::OBJECT(city VARCHAR, state VARCHAR)
) AS object_cast_type,
SYSTEM$TYPEOF(
{'city':'San Mateo','state':'CA'}::VARIANT::OBJECT(city VARCHAR, state VARCHAR)
) AS variant_cast_type;
+--------------------------------------------------------------+--------------------------------------------------------------+
| OBJECT_CAST_TYPE | VARIANT_CAST_TYPE |
|--------------------------------------------------------------+--------------------------------------------------------------|
| OBJECT(city VARCHAR(16777216), state VARCHAR(16777216))[LOB] | OBJECT(city VARCHAR(16777216), state VARCHAR(16777216))[LOB] |
+--------------------------------------------------------------+--------------------------------------------------------------+
当您将半结构化 OBJECT 或 VARIANT 值转换为结构化 OBJECT 值时,请注意以下事项:
OBJECT 值不能包含 OBJECT 类型中未指定的任何其他键。
如果有其他键,则转换失败。
如果 OBJECT 值缺少 OBJECT 类型中指定的键,则转换失败。
OBJECT 值中每个键的值将转换为该键的指定类型。
如果无法将值转换为指定类型,则转换失败。
如果键的值为 JSON 空值,则在目标值类型不支持 JSON 空值(即目标类型不是半结构化 ARRAY、OBJECT 或 VARIANT)时,该值将转换为 NULL。
例如,如果要转换为 OBJECT(city VARCHAR),则 JSON 空值将转换为 NULL,因为 VARCHAR 不支持 JSON 空值。
另一方面,如果要转换为 OBJECT(city VARIANT),则 JSON 空值不会转换为 NULL,因为 VARIANT 支持 JSON 空值。
将半结构化 OBJECT 和 VARIANT 值转换为 MAP 值¶
以下语句演示如何将半结构化 OBJECT 或 VARIANT 值转换为与值为 VARCHAR 的 VARCHAR 键关联的 MAP 值:
SELECT
SYSTEM$TYPEOF(
CAST ({'my_key':'my_value'} AS MAP(VARCHAR, VARCHAR))
) AS map_cast_type,
SYSTEM$TYPEOF(
CAST ({'my_key':'my_value'} AS MAP(VARCHAR, VARCHAR))
) AS variant_cast_type;
或者:
SELECT
SYSTEM$TYPEOF(
{'my_key':'my_value'}::MAP(VARCHAR, VARCHAR)
) AS map_cast_type,
SYSTEM$TYPEOF(
{'my_key':'my_value'}::VARIANT::MAP(VARCHAR, VARCHAR)
) AS variant_cast_type;
+------------------------------------------------+------------------------------------------------+
| MAP_CAST_TYPE | VARIANT_CAST_TYPE |
|------------------------------------------------+------------------------------------------------|
| MAP(VARCHAR(16777216), VARCHAR(16777216))[LOB] | MAP(VARCHAR(16777216), VARCHAR(16777216))[LOB] |
+------------------------------------------------+------------------------------------------------+
当您将半结构化 OBJECT 或 VARIANT 值转换为 MAP 值时,请注意以下事项:
如果键和值与指定类型不匹配,则键和值将转换为指定的类型。
如果无法将键和值转换为指定类型,则转换失败。
如果键的值为 JSON 空值,则在目标值类型不支持 JSON 空值(即目标类型不是半结构化 ARRAY、OBJECT 或 VARIANT)时,该值将转换为 NULL。
例如,如果要转换为 MAP(VARCHAR、VARCHAR),则 JSON 空值将转换为 NULL,因为 VARCHAR 不支持 JSON 空值。
另一方面,如果要转换为 MAP(VARCHAR, VARIANT),则不会将 JSON 空值转换为 NULL,因为 VARIANT 支持 JSON 空值。
将结构化类型显式转换为半结构化类型¶
若要将结构化类型的值显式转换为半结构化类型的值,可以 调用 CAST 函数,使用 :: 运算符,或调用其中一个转换函数(例如 TO_ARRAY、TO_OBJECT 或 TO_VARIANT)。
备注
结构化类型不支持 TRY_CAST。
结构化类型 |
可转换为的半结构化类型 |
---|---|
结构化 ARRAY |
ARRAY |
MAP 或结构化 OBJECT |
OBJECT |
MAP、结构化 ARRAY 或结构化 OBJECT |
VARIANT |
例如:
如果
col_structured_array
为 ARRAY(VARCHAR) 类型:CAST(col_structured_array AS ARRAY) 会返回半结构化 ARRAY 值。
CAST(col_structured_array AS VARIANT) 会返回包含半结构化 ARRAY 值的 VARIANT 值。
如果
col_structured_object
为 OBJECT(name VARCHAR, state VARCHAR) 类型:CAST(col_structured_object AS OBJECT) 会返回半结构化 OBJECT 值。
CAST(col_structured_object AS VARIANT) 会返回包含半结构化 OBJECT 值的 VARIANT 值。
如果
col_map
为 MAP(VARCHAR, VARCHAR) 类型:CAST(col_map AS OBJECT) 会返回半结构化 OBJECT 值。
CAST(col_map AS VARIANT) 会返回包含半结构化 OBJECT 值的 VARIANT 值。
请注意以下事项:
转换为半结构化 OBJECT 值时,不会保留结构化 OBJECT 值中的键顺序。
将结构化 OBJECT 或 MAP 值转换为半结构化 OBJECT 或 VARIANT 值时,任何 NULL 值都将转换为 JSON 空值。
如果将结构化 ARRAY 值转换为 VARIANT 值,则 NULL 值将按原样保留。
SELECT [1,2,NULL,3]::ARRAY(INTEGER)::VARIANT;
+---------------------------------------+ | [1,2,NULL,3]::ARRAY(INTEGER)::VARIANT | |---------------------------------------| | [ | | 1, | | 2, | | undefined, | | 3 | | ] | +---------------------------------------+
如果您要转换使用 NUMBER 键类型的 MAP 值,则 MAP 键将转换为返回的 OBJECT 值中的字符串。
隐式转换值(强制)¶
以下规则适用于从一种结构化类型的值 隐式转换(强制) 为另一种结构化类型的值:
如果两个基本对象类型相同,则可以将一个结构化类型值强制转换为另一个结构化类型值:
一种类型的 ARRAY 值可以强制转换为另一种类型的 ARRAY 值,前提是第一种元素类型可强制转换为第二种元素类型。
在以下任一情况下,一种元素类型可以强制转换为另一种元素类型:
两种类型都是数值。支持以下情况:
两者都使用相同的数值类型,但在精度和/或标度上可能有所不同。
将 NUMBER 强制转换为 FLOAT (反之亦然)。
两种类型都是时间戳。支持以下情况:
两者都使用相同的类型,但精度可能不同。
将 TIMESTAMP_LTZ 强制转换为 TIMESTAMP_TZ (反之亦然)。
例如:
ARRAY(NUMBER) 值可以强制转换为 ARRAY(DOUBLE) 值。
ARRAY(DATE) 值不能强制转换为 ARRAY(NUMBER) 值。
仅当满足以下所有条件时,具有一种类型定义的 OBJECT 值才能强制转换为具有另一种类型定义的 OBJECT 值:
两种 OBJECT 类型具有相同数量的键。
两种 OBJECT 类型为键使用相同的名称。
两种 OBJECT 类型中的键的顺序相同。
一种 OBJECT 类型中每个值的类型可以强制转换为另一种 OBJECT 类型中相应值的类型。
与结构化 ARRAY 值中的元素类型一样,只有在以下情况下,才能将一个值的类型强制转换为另一种类型:
两种类型都是数值。支持以下情况:
两者都使用相同的数值类型,但在精度和/或标度上可能有所不同。
将 NUMBER 强制转换为 FLOAT (反之亦然)。
两种类型都是时间戳。支持以下情况:
两者都使用相同的类型,但精度可能不同。
将 TIMESTAMP_LTZ 强制转换为 TIMESTAMP_TZ (反之亦然)。
例如:
OBJECT(city VARCHAR, zipcode NUMBER) 值可以强制转换为 OBJECT(city VARCHAR, zipcode DOUBLE) 值。
OBJECT(city VARCHAR, zipcode NUMBER) 值不能强制转换为 OBJECT(city VARCHAR, zipcode DATE) 值。
在以下情况下,具有一种值类型的 MAP 值可以强制转换为具有不同值类型的 MAP 值:
两种值类型都是数值。支持以下情况:
两者都使用相同的数值类型,但在精度和/或标度上可能有所不同。
将 NUMBER 强制转换为 FLOAT (反之亦然)。
两种值类型都是时间戳。支持以下情况:
两者都使用相同的类型,但精度可能不同。
将 TIMESTAMP_LTZ 强制转换为 TIMESTAMP_TZ (反之亦然)。
例如,MAP(VARCHAR,NUMBER)值可以强制转换为 MAP(VARCHAR,DOUBLE)值。
如果两种键类型都使用只有精度不同的相同整数 NUMERIC 类型,则可以将具有一种键类型的 MAP 值强制转换为不同键类型的 MAP 值。
例如,MAP(VARCHAR, NUMBER) 值不能强制转换为 MAP(NUMBER, NUMBER) 值。
结构化类型值不能强制转换为半结构化值(反之亦然)。
VARCHAR 值不能强制转换为结构化类型值。
从一种结构化类型转换为另一种结构化类型¶
您可以 调用 CAST 函数或使用 :: 运算符 从一个结构化类型的值转换为另一个结构化类型的值。您可以在以下结构化类型之间转换值:
对于结构化 ARRAYs:
对于结构化 OBJECTs:
对于 MAP 值:
您可以将具有特定类型键和值的 MAP 值转换为具有不同类型键和值的 MAP 值。
您可以将 MAP 值转换为结构化 OBJECT 值。
备注
结构化类型不支持 TRY_CAST。
如果无法将值从一种类型转换为另一种类型,则转换失败。例如,尝试将 ARRAY(BOOLEAN) 值转换为 ARRAY(DATE) 值失败。
示例:从一种类型的 ARRAY 值转换为另一种类型¶
以下示例将 ARRAY(NUMBER) 值转换为 ARRAY(VARCHAR) 值:
SELECT CAST(
CAST([1,2,3] AS ARRAY(NUMBER))
AS ARRAY(VARCHAR)) AS cast_array;
+------------+
| CAST_ARRAY |
|------------|
| [ |
| "1", |
| "2", |
| "3" |
| ] |
+------------+
示例:在 OBJECT 值中更改键值对顺序¶
以下示例更改了结构化 OBJECT 值中键值对的顺序:
SELECT CAST(
{'city': 'San Mateo','state': 'CA'}::OBJECT(city VARCHAR, state VARCHAR)
AS OBJECT(state VARCHAR, city VARCHAR)) AS object_value_order;
+-----------------------+
| OBJECT_VALUE_ORDER |
|-----------------------|
| { |
| "state": "CA", |
| "city": "San Mateo" |
| } |
+-----------------------+
示例:更改 OBJECT 值中的键名称¶
要更改结构化 OBJECT 值中的键名称,请指定 CAST 末尾的 RENAME FIELDS 关键字。例如:
SELECT CAST({'city':'San Mateo','state': 'CA'}::OBJECT(city VARCHAR, state VARCHAR)
AS OBJECT(city_name VARCHAR, state_name VARCHAR) RENAME FIELDS) AS object_value_key_names;
+-----------------------------+
| OBJECT_VALUE_KEY_NAMES |
|-----------------------------|
| { |
| "city_name": "San Mateo", |
| "state_name": "CA" |
| } |
+-----------------------------+
示例:向 OBJECT 值添加键¶
如果要转换到的类型具有原始结构化 OBJECT 值中不存在的其他键值对,请在 CAST 的末尾指定 ADD FIELDS 关键字。例如:
SELECT CAST({'city':'San Mateo','state': 'CA'}::OBJECT(city VARCHAR, state VARCHAR)
AS OBJECT(city VARCHAR, state VARCHAR, zipcode NUMBER) ADD FIELDS) AS add_fields;
+------------------------+
| ADD_FIELDS |
|------------------------|
| { |
| "city": "San Mateo", |
| "state": "CA", |
| "zipcode": null |
| } |
+------------------------+
新添加的键的值将设置为 NULL。如果要为这些键赋值,请改为调用 OBJECT_INSERT 函数。
构造结构化 ARRAY、结构化 OBJECT 和 MAP 值¶
以下部分解释了如何构造结构化 ARRAY、结构化 OBJECT 和 MAP 值。
使用 SQL 函数构造结构化 ARRAY 和 OBJECT 值¶
以下函数构造半结构化 ARRAY 值:
以下函数构造半结构化 OBJECT 值:
若要构造结构化 ARRAY 或 OBJECT 值,请使用这些函数并显式转换函数的返回值。例如:
SELECT ARRAY_CONSTRUCT(10, 20, 30)::ARRAY(NUMBER);
SELECT OBJECT_CONSTRUCT(
'oname', 'abc',
'created_date', '2020-01-18'::DATE
)::OBJECT(
oname VARCHAR,
created_date DATE
);
有关详细信息,请参阅 将半结构化类型显式转换为结构化类型。
备注
不能将结构化 ARRAY、结构化 OBJECT 或 MAP 值传递给这些函数。这样做会导致结构化类型被隐式转换为半结构化类型,而这是不被允许的(如 隐式转换值(强制) 中所述)。
使用 ARRAY 和 OBJECT 常量构造结构化 ARRAY 和 OBJECT 值¶
当您指定 ARRAY 常量 或 OBJECT 常量 时,您指定的是半结构化 ARRAY 或 OBJECT 值。
要构造结构化 ARRAY 或 OBJECT 值,必须显式转换表达式。例如:
SELECT [10, 20, 30]::ARRAY(NUMBER);
SELECT {
'oname': 'abc',
'created_date': '2020-01-18'::DATE
}::OBJECT(
oname VARCHAR,
created_date DATE
);
有关详细信息,请参阅 将半结构化类型显式转换为结构化类型。
构造 MAP 值¶
要构造 MAP 值,请构造半结构化 OBJECT 值,并将 OBJECT 值转换为 MAP 值。
例如,以下语句均生成 MAP 值 {'city'->'San Mateo','state'->'CA'}
:
SELECT OBJECT_CONSTRUCT(
'city', 'San Mateo',
'state', 'CA'
)::MAP(
VARCHAR,
VARCHAR
);
SELECT {
'city': 'San Mateo',
'state': 'CA'
}::MAP(
VARCHAR,
VARCHAR
);
以下语句生成 MAP 值 {-10->'CA',-20->'OR'}
:
SELECT {
'-10': 'CA',
'-20': 'OR'
}::MAP(
NUMBER,
VARCHAR
);
有关详细信息,请参阅 将半结构化 OBJECT 和 VARIANT 值转换为 MAP 值。
在结构化类型值中处理键、值和元素¶
以下各部分介绍如何在结构化类型值中使用键、值和元素。
从结构化 OBJECT 值中获取键列表¶
要获取结构化 OBJECT 值中的键列表,请调用 OBJECT_KEYS 函数:
SELECT OBJECT_KEYS({'city':'San Mateo','state':'CA'}::OBJECT(city VARCHAR, state VARCHAR));
如果输入是结构化 OBJECT 值,则函数返回包含键的 ARRAY(VARCHAR) 值。如果输入是半结构化 OBJECT 值,则函数返回 ARRAY 值。
获取 MAP 值中的键列表¶
要获取 MAP 值中的键列表,请调用 MAP_KEYS 函数:
SELECT MAP_KEYS({'my_key':'my_value'}::MAP(VARCHAR,VARCHAR));
访问结构化类型值中的值和元素¶
您可以使用以下方法访问结构化 ARRAY、结构化 OBJECT 和 MAP 值中的值和元素:
返回的值和元素具有为结构化值指定的类型,而不是 VARIANT。
下面的示例将半结构化 ARRAY 值的第一个元素和 ARRAY(VARCHAR) 值传递给 SYSTEM$TYPEOF 函数,以返回该元素的数据类型:
SELECT
SYSTEM$TYPEOF(
ARRAY_CONSTRUCT('San Mateo')[0]
) AS semi_structured_array_element,
SYSTEM$TYPEOF(
CAST(
ARRAY_CONSTRUCT('San Mateo') AS ARRAY(VARCHAR)
)[0]
) AS structured_array_element;
+-------------------------------+-----------------------------+
| SEMI_STRUCTURED_ARRAY_ELEMENT | STRUCTURED_ARRAY_ELEMENT |
|-------------------------------+-----------------------------|
| VARIANT[LOB] | VARCHAR(16777216)[LOB] |
+-------------------------------+-----------------------------+
请注意以下事项:
将结构化 OBJECT 值传递给 GET 或 GET_IGNORE_CASE 函数时,必须为键指定常量。
如果要将 MAP 或结构化 ARRAY 值传递给 GET 函数,则无需指定常量。
如果要将 MAP 值传递给 GET_IGNORE_CASE 函数,也不需要指定常量。
将结构化 OBJECT、结构化 ARRAY 或 MAP 值传递给 GET_PATH 函数时,必须为路径名指定一个常量。
对于结构化 OBJECT 值,如果使用不存在的 OBJECT 键或路径,则会发生编译时错误。
相反,当您在半结构化 OBJECT 值中使用不存在的索引、键或路径时,该函数将返回 NULL。
确定结构化 ARRAY 值的大小¶
要确定结构化 ARRAY 值的大小,请将 ARRAY 值传递给 ARRAY_SIZE 函数:
SELECT ARRAY_SIZE([1,2,3]::ARRAY(NUMBER));
确定 MAP 值的大小¶
要确定 MAP 值的大小,请将 MAP 值传递给 MAP_SIZE 函数:
SELECT MAP_SIZE({'my_key':'my_value'}::MAP(VARCHAR,VARCHAR));
在结构化 ARRAY 值中查找元素¶
要确定结构化 ARRAY 值中是否存在元素,请调用 ARRAY_CONTAINS 函数。例如:
SELECT ARRAY_CONTAINS(10, [1, 10, 100]::ARRAY(NUMBER));
要确定元素在结构化 ARRAY 值中的位置,请调用 ARRAY_POSITION 函数。例如:
SELECT ARRAY_POSITION(10, [1, 10, 100]::ARRAY(NUMBER));
确定 MAP 值是否包含键¶
若要确定 MAP 值是否包含键,请调用 MAP_CONTAINS_KEY 函数:
例如:
SELECT MAP_CONTAINS_KEY('key_to_find', my_map);
SELECT MAP_CONTAINS_KEY(10, my_map);
比较值¶
以下部分说明如何比较值:
将结构化值与半结构化值进行比较¶
不能将结构化 ARRAY、结构化 OBJECT 或 MAP 值与半结构化 ARRAY、OBJECT 或 VARIANT 值进行比较。
将结构化值与其他结构化值进行比较¶
可以比较两个相同类型的值(例如,两个结构化 ARRAY 值、两个结构化 OBJECT 值或两个 MAP 值)。
目前,支持使用以下比较运算符来比较结构化类型值:
=
!=
<
<=
>=
>
比较两个结构化值是否相等时,请注意以下事项:
如果一种类型不能 强制转换 为另一种类型,则比较失败。
当您比较具有数字键的 MAP 值时,这些键将作为数字(而不是 VARCHAR 值)进行比较。
使用 <
, <=
, >=
, or >
比较两个结构化值时,将按字母顺序比较结构化值字段。例如,以下值:
{'a':2,'b':1}::OBJECT(b INTEGER,a INTEGER)
大于:
{'a':1,'b':2}::OBJECT(b INTEGER,a INTEGER)
确定两个 ARRAY 值是否重叠¶
如果需要确定两个结构化的 ARRAY 值元素是否重叠,请调用 ARRAYS_OVERLAP 函数。例如:
SELECT ARRAYS_OVERLAP(numeric_array, other_numeric_array);
ARRAY 值必须属于 同类的类型。
不能将半结构化 ARRAY 值和结构化 ARRAY 值传递给此函数。两个 ARRAY 值必须同时是结构化的或半结构化的。
转换结构化类型的值¶
以下部分介绍如何转换结构化 ARRAY、结构化 OBJECT 和 MAP 值:
转换结构化 ARRAY 值¶
当将结构化 ARRAY 值传递给这些函数时,这些函数将返回相同类型的结构化 ARRAY 值:
接下来的部分将介绍这些函数如何处理结构化 ARRAY 值。
将元素添加到 ARRAY 值的函数¶
以下函数用于将元素添加到 ARRAY 值:
对于这些函数,元素的类型必须 可强制转换为 ARRAY 值的类型。
例如,以下调用成功,因为 NUMBER 值可强制转换为 DOUBLE 值(ARRAY 值的类型):
SELECT ARRAY_APPEND( [1,2]::ARRAY(DOUBLE), 3::NUMBER );
以下调用成功,因为 VARCHAR 值可强制转换为 DOUBLE 值:
SELECT ARRAY_APPEND( [1,2]::ARRAY(DOUBLE), '3' );
以下调用失败,因为 DATE 值无法强制转换为 NUMBER 值:
SELECT ARRAY_APPEND( [1,2]::ARRAY(NUMBER), '2022-02-02'::DATE );
可接受多个 ARRAY 值作为输入的函数¶
以下函数接受多个 ARRAY 值作为输入实参:
调用这些函数时,两个实参都必须是结构化 ARRAY 值或半结构化 ARRAY 值。例如,以下调用失败,因为一个实参是结构化 ARRAY 值,而另一个实参是半结构化 ARRAY 值:
SELECT ARRAY_CAT( [1,2]::ARRAY(NUMBER), ['3','4'] );
SELECT ARRAY_CAT( [1,2], ['3','4']::ARRAY(VARCHAR) );
ARRAY_EXCEPT 函数返回与第一个实参中的 ARRAY 值相同类型的 ARRAY 值。
ARRAY_CAT 和 ARRAY_INTERSECTION 函数会返回一个类型为 ARRAY 的值,其类型可以容纳两种输入值类型。
例如,以下对 ARRAY_CAT 的调用以两种结构化 ARRAY 值的方式传递:
第一种结构化 ARRAY 值不允许 NULLs,并且包含标度为 0 (NUMBER(38, 0)) 的 NUMBER 值。
第二个结构化 ARRAY 值包含 NULL 和一个标度为 1 的 NUMBER 值。
ARRAY_CAT 返回的 ARRAY 值允许 NULLs 并包含标度为 1 的 NUMBER 值。
SELECT
ARRAY_CAT(
[1, 2, 3]::ARRAY(NUMBER NOT NULL),
[5.5, NULL]::ARRAY(NUMBER(2, 1))
) AS concatenated_array,
SYSTEM$TYPEOF(concatenated_array);
+--------------------+-----------------------------------+
| CONCATENATED_ARRAY | SYSTEM$TYPEOF(CONCATENATED_ARRAY) |
|--------------------+-----------------------------------|
| [ | ARRAY(NUMBER(38,1))[LOB] |
| 1, | |
| 2, | |
| 3, | |
| 5.5, | |
| undefined | |
| ] | |
+--------------------+-----------------------------------+
对于 ARRAY_CAT 函数,第二个实参中的 ARRAY 值必须 可强制转换 为第一个实参中的类型。
对于 ARRAY_EXCEPT 和 ARRAY_INTERSECTION 函数,第二个实参中的 ARRAY 值必须与第一个实参中的 ARRAY 值 属于同类。
例如,以下调用成功,因为 ARRAY(NUMBER) 值与 ARRAY(DOUBLE) 值属于同类:
SELECT ARRAY_EXCEPT( [1,2]::ARRAY(NUMBER), [2,3]::ARRAY(DOUBLE) );
以下调用失败,因为 ARRAY(NUMBER) 值与 ARRAY(VARCHAR) 值不属于同类:
SELECT ARRAY_EXCEPT( [1,2]::ARRAY(NUMBER), ['2','3']::ARRAY(VARCHAR) );
转换结构化 OBJECT 值¶
以下部分说明如何返回已从另一个结构化 OBJECT 值转换而来的结构化 OBJECT 值:
若要更改键值对的顺序、重命名键或在不指定值的情况下添加键,请使用 CAST 函数或 :: 运算符。有关详细信息,请参阅 从一种结构化类型转换为另一种结构化类型。
移除键值对¶
若要从移除了特定键值对的现有 OBJECT 值返回包含键值对的新 OBJECT 值,请调用 OBJECT_DELETE 函数。
调用此函数时,请注意以下事项:
对于作为键的实参,您必须指定常量。
如果指定的键不是 OBJECT 类型定义的一部分,则调用失败。例如,以下调用失败,因为 OBJECT 值不包含指定的键
zip_code
:SELECT OBJECT_DELETE( {'city':'San Mateo','state':'CA'}::OBJECT(city VARCHAR,state VARCHAR), 'zip_code' );
093201 (23001): Function OBJECT_DELETE: expected structured object to contain field zip_code but it did not.
该函数返回一个结构化的 OBJECT 值。OBJECT 值的类型会排除已删除的键。例如,假设您移除了
city
键:SELECT OBJECT_DELETE( {'city':'San Mateo','state':'CA'}::OBJECT(city VARCHAR,state VARCHAR), 'city' ) AS new_object, SYSTEM$TYPEOF(new_object);
该函数会返回
OBJECT(state VARCHAR)
类型的 OBJECT 值,其中不包含city
键。+-----------------+--------------------------------------+ | NEW_OBJECT | SYSTEM$TYPEOF(NEW_OBJECT) | |-----------------+--------------------------------------| | { | OBJECT(state VARCHAR(16777216))[LOB] | | "state": "CA" | | | } | | +-----------------+--------------------------------------+
如果该函数从 OBJECT 值中移除所有键,则该函数将返回
OBJECT()
类型的空结构化 OBJECT 值。SELECT OBJECT_DELETE( {'state':'CA'}::OBJECT(state VARCHAR), 'state' ) AS new_object, SYSTEM$TYPEOF(new_object);
+------------+---------------------------+ | NEW_OBJECT | SYSTEM$TYPEOF(NEW_OBJECT) | |------------+---------------------------| | {} | OBJECT()[LOB] | +------------+---------------------------+
当结构化 OBJECT 值的类型包括键值对时,这些对的名称和类型将包含在类型的括号中(例如,OBJECT(city VARCHAR))。由于空结构化 OBJECT 值不包含键值对,因此括号为空。
插入键值对并更新值¶
若要返回包含现有 OBJECT 值的键值对的新 OBJECT 值,并具有其他键值对或键的新值,请调用 OBJECT_INSERT 函数。
调用此函数时,请注意以下事项:
对于作为键的实参,您必须指定常量。
当
updateFlag
实参为 FALSE(插入新的键值对时):如果指定一个存在于 OBJECT 值的键,则会发生错误。
SELECT OBJECT_INSERT( {'city':'San Mateo','state':'CA'}::OBJECT(city VARCHAR,state VARCHAR), 'city', 'San Jose', false );
093202 (23001): Function OBJECT_INSERT: expected structured object to not contain field city but it did.
该函数返回一个结构化的 OBJECT 值。OBJECT 值的类型包括新插入的键。例如,假设您添加具有 FLOAT 值
94402
的zipcode
键:SELECT OBJECT_INSERT( {'city':'San Mateo','state':'CA'}::OBJECT(city VARCHAR,state VARCHAR), 'zip_code', 94402::FLOAT, false ) AS new_object, SYSTEM$TYPEOF(new_object) AS type;
+-------------------------------------+---------------------------------------------------------------------------------------+ | NEW_OBJECT | TYPE | |-------------------------------------+---------------------------------------------------------------------------------------| | { | OBJECT(city VARCHAR(16777216), state VARCHAR(16777216), zip_code FLOAT NOT NULL)[LOB] | | "city": "San Mateo", | | | "state": "CA", | | | "zip_code": 9.440200000000000e+04 | | | } | | +-------------------------------------+---------------------------------------------------------------------------------------+
插入值的类型决定了添加到 OBJECT 类型定义中的类型。在这种情况中,
zipcode
的值是转换为 FLOAT 的值,因此zipcode
的类型为 FLOAT。
当
updateFlag
实参为 TRUE 时(当您替换现有键值对时):如果指定的键并未存在于 OBJECT 值中,则会发生错误。
该函数返回相同类型的结构化 OBJECT 值。
将插入值的类型 强制转换 为现有键的类型。
从现有 OBJECT 中选择键值对¶
若要从现有 OBJECT 值返回包含选定键值对的新 OBJECT 值,请调用 OBJECT_PICK 函数。
调用此函数时,请注意以下事项:
对于作为键的实参,您必须指定常量。
不能将键的 ARRAY 作为第二个实参进行传递。必须将每个键指定为单独的实参。
该函数返回一个结构化的 OBJECT 值。OBJECT 值的类型包括按指定顺序排列的键。
例如,假设您按以下顺序选择
state
和city
键:SELECT OBJECT_PICK( {'city':'San Mateo','state':'CA','zip_code':94402}::OBJECT(city VARCHAR,state VARCHAR,zip_code DOUBLE), 'state', 'city') AS new_object, SYSTEM$TYPEOF(new_object);
该函数返回
OBJECT(state VARCHAR, city VARCHAR)
类型的 OBJECT 值。+-----------------------+--------------------------------------------------------------+ | NEW_OBJECT | SYSTEM$TYPEOF(NEW_OBJECT) | |-----------------------+--------------------------------------------------------------| | { | OBJECT(state VARCHAR(16777216), city VARCHAR(16777216))[LOB] | | "state": "CA", | | | "city": "San Mateo" | | | } | | +-----------------------+--------------------------------------------------------------+
转换 MAP 值¶
要转换 MAP 值,请使用以下函数:
处理结构化类型¶
以下部分介绍如何使用不同的 SQL 函数,以及使用结构化类型的值设置运算符:
将 FLATTEN 函数用于结构化类型的值¶
您可以将结构化 ARRAY、结构化 OBJECT 和 MAP 值传递给 FLATTEN 函数。与半结构化数据类型一样,您可以使用 PATH 实参来指定要展平的值。
如果要展平的值是结构化 ARRAY 值,并且 RECURSIVE 实参为 FALSE,则
value
列包含与 ARRAY 值相同的类型值。例如:
SELECT value, SYSTEM$TYPEOF(value) FROM TABLE(FLATTEN(INPUT => [1.08, 2.13, 3.14]::ARRAY(DOUBLE)));
+-------+----------------------+ | VALUE | SYSTEM$TYPEOF(VALUE) | |-------+----------------------| | 1.08 | FLOAT[DOUBLE] | | 2.13 | FLOAT[DOUBLE] | | 3.14 | FLOAT[DOUBLE] | +-------+----------------------+
如果要展平的值为 MAP 值,RECURSIVE 实参为 FALSE,则
key
列包含与 MAP 键类型相同的键,并且value
列包含与 MAP 值类型相同的值。例如:
SELECT key, SYSTEM$TYPEOF(key), value, SYSTEM$TYPEOF(value) FROM TABLE(FLATTEN(INPUT => {'my_key': 'my_value'}::MAP(VARCHAR, VARCHAR)));
+--------+------------------------+----------+------------------------+ | KEY | SYSTEM$TYPEOF(KEY) | VALUE | SYSTEM$TYPEOF(VALUE) | |--------+------------------------+----------+------------------------| | my_key | VARCHAR(16777216)[LOB] | my_value | VARCHAR(16777216)[LOB] | +--------+------------------------+----------+------------------------+
否则,
key
和value
列的类型为 VARIANT。
对于 MAP 值,返回的键和值的顺序是不确定的。
使用 PARSE_JSON 函数¶
PARSE_JSON 函数不返回结构化类型。
将结构化类型与集合运算符和 CASE 表达式一起使用¶
您可以在以下表达式中使用结构化 ARRAY、结构化 OBJECT 和 MAP 值:
对于集运算符,如果在不同的表达式中使用不同的类型(例如,如果一种类型是 ARRAY(NUMBER),另一种类型是 ARRAY(DOUBLE)),则一种类型将 强制转换 为另一种类型。
处理其他半结构化函数¶
以下函数不接受结构化 ARRAY、结构化 OBJECT 或 MAP 值作为输入实参:
将结构化类型值作为输入传递会导致错误。
使用驱动程序访问应用程序中的结构化类型¶
在使用驱动程序(例如 ODBC 或 JDBC 驱动程序、Snowflake Connector for Python 等)的应用程序中,会以半结构化类型值的形式返回结构化类型值。例如:
结构化 ARRAY 列中的值会以半结构化 ARRAY 值的形式返回到客户端应用程序。
结构化 OBJECT 或 MAP 列中的值会以半结构化 OBJECT 值的形式返回到客户端应用程序。
备注
对于使用 JDBC 驱动程序的客户端应用程序,如果要检索的查询结果包含具有 NULL 值的结构化 ARRAY 值,ResultSet.getArray()
方法将返回错误。
要检索字符串表示,请使用 ResultSet.getString()
方法:
String result = resultSet.getString(1);
将结构化类型与用户定义函数 (UDFs) 和存储过程结合使用¶
在 SQL、Snowflake Scripting、Java、Python 或 Scala 中创建用户定义函数 (UDF)、用户定义表函数 (UDTF) 或存储过程时,可以在实参和返回值中使用结构化类型。例如:
CREATE OR REPLACE FUNCTION my_udf(
location OBJECT(city VARCHAR, zipcode NUMBER, val ARRAY(BOOLEAN)))
RETURNS VARCHAR
AS
$$
...
$$;
CREATE OR REPLACE FUNCTION my_udtf(check BOOLEAN)
RETURNS TABLE(col1 ARRAY(VARCHAR))
AS
$$
...
$$;
CREATE OR REPLACE PROCEDURE my_procedure(values ARRAY(INTEGER))
RETURNS ARRAY(INTEGER)
LANGUAGE SQL
AS
$$
...
$$;
CREATE OR REPLACE FUNCTION my_function(values ARRAY(INTEGER))
RETURNS ARRAY(INTEGER)
LANGUAGE PYTHON
RUNTIME_VERSION=3.10
AS
$$
...
$$;
备注
在 UDFs、UDTFs 以及 JavaScript 中的存储过程尚不支持结构化类型。
查看有关结构化类型的信息¶
以下部分介绍可用于查看有关结构化类型的信息的视图和命令:
使用 SHOW COLUMNS 命令查看结构化类型信息¶
在 SHOW COLUMNS 命令的输出中,data_type
列包含有关元素、键和值类型的信息。
使用 DESCRIBE 和其他 SHOW 命令查看结构化类型信息¶
以下命令的输出包括有关结构化类型的信息:
例如,在 DESCRIBE RESULT 输出中,MAP (VARCHAR、VARCHAR)列的行包含 type
列中的以下值:
map(VARCHAR(16777216), VARCHAR(16777216))
ARRAY(NUMBER) 列的行包含 type
列中的以下值:
ARRAY(NUMBER(38,0))
查看有关数据库中使用的结构化类型的信息¶
对于结构化类型的列,INFORMATION_SCHEMA COLUMNS 视图 仅提供与列的基本数据类型(ARRAY、OBJECT 或 MAP)有关的信息。
例如,data_type
列仅包含 ARRAY
、OBJECT
或 MAP
。该列不包括元素、键或值的类型。
要查看有关元素、键和值类型的信息,请使用以下视图:
有关结构化 ARRAY 类型中的元素类型的信息,请查询 INFORMATION_SCHEMA 中的 ELEMENT_TYPES 视图 或 ACCOUNT_USAGE 中的 ELEMENT_TYPES 视图。
有关结构化 OBJECT 和 MAP 类型中的键和值的信息,请查询 INFORMATION_SCHEMA 中的 FIELDS 视图 或 ACCOUNT_USAGE 中的 FIELDS 视图。