结构化数据类型¶
结构化类型是 ARRAY、OBJECT 或 MAP,包含具有特定 Snowflake 数据类型 的元素或键值对。以下是结构化类型的示例:
INTEGER 元素的 ARRAY。
包含 VARCHAR 和 NUMBER 键值对的 OBJECT。
将 VARCHAR 键与 DOUBLE 值关联的 MAP。
您可以通过以下方式使用结构化类型:
您可以在 Iceberg 表 中定义结构化类型列。
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 的键。对象定义中的每个
key
都必须是唯一的。键的顺序是对象定义的一部分。不允许以不同的顺序比较具有相同键的两个 OBJECTs。(发生编译时错误。)
如果不指定任何键,但指定括号(即,如果使用 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), num NUMBER(38,0) NOT NULL )[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。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。在以下情况下会发生错误:
转换结构化类型和半结构化类型¶
下表总结了将结构化 OBJECTs、结构化 ARRAYs 和 MAPs 转换 为半结构化 OBJECTs、ARRAYs 和 VARIANTs 的规则(反之亦然)。
源数据类型 |
目标数据类型 |
||
---|---|---|---|
半结构化 ARRAY |
结构化 ARRAY |
✔ |
❌ |
半结构化 OBJECT |
|
✔ |
❌ |
半结构化 VARIANT |
|
✔ |
❌ |
结构化 ARRAY |
半结构化 ARRAY |
✔ |
❌ |
|
半结构化 OBJECT |
✔ |
❌ |
|
半结构化 VARIANT |
✔ |
❌ |
以下各部分将更详细地说明这些规则。
将半结构化类型显式转换为结构化类型¶
要将半结构化对象显式转换为结构化类型,您可以 调用 CAST 函数或使用 :: 运算符。
备注
结构化类型不支持 TRY_CAST。
您只能将以下半结构化对象转换为相应的结构化类型;否则,将发生运行时错误。
半结构化类型 |
可转换为的结构化类型 |
---|---|
ARRAY |
结构化 ARRAY |
OBJECT |
MAP 或结构化 OBJECT |
VARIANT |
MAP 或者结构化 ARRAY 或 OBJECT |
接下来的部分将更详细地说明如何转换类型:
将半结构化 ARRAYs 和 VARIANTs 转换为结构化 ARRAYs¶
以下步骤演示了如何将半结构化 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 空值。
将半结构化 OBJECTs 和 VARIANTs 转换为结构化 OBJECTs¶
以下步骤演示如何将半结构化 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 (城市 VARCHAR),则 JSON 空值将转换为 NULL,因为 VARCHAR 不支持 JSON 空值。
另一方面,如果要转换为 OBJECT (城市 VARIANT),则 JSON 空值不会转换为 NULL,因为 VARIANT 支持 JSON 空值。
将半结构化 OBJECTs 和 VARIANTs 转换为 MAPs¶
以下语句演示如何将半结构化 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(名称 VARCHAR,状态 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 类型中相应值的类型。
与结构化 ARRAYs 中的元素类型一样,只有在以下情况下,才能将一个值的类型强制转换为另一种类型:
两种类型都是数值。支持以下情况:
两者都使用相同的数值类型,但在精度和/或标度上可能有所不同。
将 NUMBER 强制转换为 FLOAT (反之亦然)。
两种类型都是时间戳。支持以下情况:
两者都使用相同的类型,但精度可能不同。
将 TIMESTAMP_LTZ 强制转换为 TIMESTAMP_TZ (反之亦然)。
例如:
OBJECT (城市 VARCHAR,邮政编码 NUMBER)可以强制转换为 OBJECT (城市 VARCHAR,邮政编码 DOUBLE)。
OBJECT (城市 VARCHAR,邮政编码 NUMBER)不能强制转换为 OBJECT (城市 VARCHAR,邮政编码 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:
对于 MAPs:
您可以将具有特定类型键和值的 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)
);
示例:在 OBJECT 中更改键值对顺序¶
以下示例更改了结构化 OBJECT 中键值对的顺序:
SELECT CAST(
{'city': 'San Mateo','state': 'CA'}::OBJECT(city VARCHAR, state VARCHAR)
AS OBJECT(state VARCHAR, city VARCHAR)
);
示例:更改 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);
+------------------------------------------------------------------------------+
| CAST({'CITY':'SAN MATEO','STATE': 'CA'}::OBJECT(CITY VARCHAR, STATE VARCHAR) |
| AS OBJECT(CITY_NAME VARCHAR, STATE_NAME VARCHAR) RENAME FIELDS) |
|------------------------------------------------------------------------------|
| { |
| "city_name": "San Mateo", |
| "state_name": "CA" |
| } |
+------------------------------------------------------------------------------+
示例:向 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);
+------------------------------------------------------------------------------+
| CAST({'CITY':'SAN MATEO','STATE': 'CA'}::OBJECT(CITY VARCHAR, STATE VARCHAR) |
| AS OBJECT(CITY VARCHAR, STATE VARCHAR, ZIPCODE NUMBER) ADD FIELDS) |
|------------------------------------------------------------------------------|
| { |
| "city": "San Mateo", |
| "state": "CA", |
| "zipcode": null |
| } |
+------------------------------------------------------------------------------+
新添加的键的值将设置为 NULL。如果要为这些键赋值,请改为调用 OBJECT_INSERT 函数。
构造结构化 ARRAYs、结构化 OBJECTs 和 MAPs¶
以下部分解释了如何构造结构化 ARRAYs、结构化 OBJECTs 和 MAPs。
使用 SQL 函数构造结构化 ARRAYs 和 OBJECTs¶
以下函数构造半结构化 ARRAYs:
以下函数构造半结构化 OBJECTs:
若要构造结构化 ARRAY 或 OBJECT,请使用这些函数并显式转换函数的返回值。例如:
SELECT ARRAY_CONSTRUCT(10, 20, 30)::ARRAY(NUMBER);
SELECT OBJECT_CONSTRUCT(
'name', 'abc',
'created_date', '2020-01-18'::DATE
)::OBJECT(
name VARCHAR,
created_date DATE
);
有关详细信息,请参阅 将半结构化类型显式转换为结构化类型。
备注
不能将结构化 ARRAYs、结构化 OBJECTs 或 MAPs 传递给这些函数。这样做将导致结构化类型被隐式转换为半结构化类型,这是不允许的(如 隐式转换值(强制) 中所述)。
使用 ARRAY 和 OBJECT 常量构造结构化 ARRAYs 和 OBJECTs¶
当您指定 ARRAY 常量 或 :ref:`OBJECT 常量 <label-object_constant>`时,您指定的是半结构化 ARRAY 或 OBJECT。
要构造结构化 ARRAY 或 OBJECT,必须显式转换表达式。例如:
SELECT [10, 20, 30]::ARRAY(NUMBER);
SELECT {
'name': 'abc',
'created_date': '2020-01-18'::DATE
}::OBJECT(
name VARCHAR,
created_date DATE
);
有关详细信息,请参阅 将半结构化类型显式转换为结构化类型。
构造 MAP¶
要构造 MAP,请构造一个半结构化对象,并将 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
)
有关详细信息,请参阅 将半结构化 OBJECTs 和 VARIANTs 转换为 MAPs。
在结构化类型中处理键、值和元素¶
以下各部分介绍如何在结构化类型中使用值和元素。
从结构化 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));
访问结构化类型中的值和元素¶
您可以使用以下方法访问结构化 ARRAYs、结构化 OBJECTs和 MAPs 中的值和元素:
返回的值和元素具有为对象指定的类型,而不是 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 键或路径,则会发生编译时错误。
相反,当您在半结构化对象中使用不存在的索引、键或路径时,该函数将返回 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 进行比较。
将结构化对象与其他结构化对象进行比较¶
您可以比较两个相同类型的对象(例如两个结构化 ARRAYs、两个结构化 OBJECTs 或两个 MAPs)。
目前,支持使用以下比较运算符来比较结构化类型:
=
!=
<
<=
>=
>
比较两个结构化对象是否相等时,请注意以下事项:
如果一种类型不能 强制转换 为另一种类型,则比较失败。
当您比较具有数字键的 MAPs 时,这些键将作为数字(而不是 VARCHAR 值)进行比较。
使用 <
, <=
, >=
, or >
比较两个结构化对象时,将按字母顺序比较结构化对象字段。例如,以下对象:
{'a':2,'b':1}::OBJECT(b INTEGER,a INTEGER)
大于:
{'a':1,'b':2}::OBJECT(b INTEGER,a INTEGER)
确定两个 ARRAYs 是否重叠¶
如果需要确定两个结构化的 ARRAYs 元素是否重叠,请调用 ARRAYS_OVERLAP 函数。例如:
SELECT ARRAYS_OVERLAP(numeric_array, other_numeric_array);
ARRAYs 必须属于 同类的类型。
请注意,不能将半结构化 ARRAY 和结构化 ARRAY 传递给此函数。两个 ARRAYs 必须同时是结构化的或半结构化的。
转换结构化类型¶
以下部分介绍如何转换结构化 ARRAYs、结构化 OBJECTs 和 MAPs:
转换结构化 ARRAYs¶
当将结构化 ARRAY 传递给这些函数时,这些函数将返回相同类型的结构化 ARRAY:
接下来的部分将介绍这些函数如何处理结构化 ARRAYs。
将元素添加到数组的函数¶
以下函数用于将元素添加到 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 );
可接受多个 ARRAYs 作为输入的函数¶
以下函数接受多个 ARRAYs 作为输入实参:
调用这些函数时,两个实参都必须是结构化 ARRAYs 或半结构化 ARRAYs。例如,以下调用失败,因为一个实参是结构化 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 的调用以两种结构化 ARRAYs 的方式传递:
第一种结构化 ARRAY 不允许 NULLs,并且包含标度为 0 的 NUMBER 值。(NUMBER 为 NUMBER (38, 0)。)
第二个结构化 ARRAY 包含 NULL 和一个标度为 1 的数字。
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) );
转换结构化 OBJECTs¶
以下部分说明如何返回已从另一个结构化 OBJECT 转换而来的结构化 OBJECT:
如果需要更改键值对的顺序、重命名键或在不指定值的情况下添加键,请使用 CAST 函数或 :: 运算符。有关详细信息,请参阅 从一种结构化类型转换为另一种结构化类型。
移除键值对¶
若要从移除了特定键值对的现有对象返回包含键值对的新对象,请调用 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$TYPE_OF(new_object);
该函数会返回
OBJECT(state VARCHAR)
类型的 OBJECT,其中不包含city
键。+-----------------+--------------------------------------+ | NEW_OBJECT | SYSTEM$TYPEOF(NEW_OBJECT) | |-----------------+--------------------------------------| | { | OBJECT(state VARCHAR(16777216))[LOB] | | "state": "CA" | | | } | | +-----------------+--------------------------------------+
如果该函数从对象中移除所有键,则该函数将返回 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 (城市 VARCHAR))。由于空结构化 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 的类型包括新插入的键。例如,假设您添加具有 DOUBLE 值
94402
的zipcode
键:SELECT OBJECT_INSERT( {'city':'San Mateo','state':'CA'}::OBJECT(city VARCHAR,state VARCHAR), 'zip_code', 94402::DOUBLE, false ) AS new_object, SYSTEM$TYPEOF(new_object);
该函数返回类型 OBJECT (城市 VARCHAR、州 VARCHAR、邮政编码 DOUBLE)的 OBJECT:
+-------------------------------------+---------------------------------------------------------------------------------------+ | NEW_OBJECT | SYSTEM$TYPEOF(NEW_OBJECT) | |-------------------------------------+---------------------------------------------------------------------------------------| | { | 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
的值是转换为 DOUBLE 的值,因此zipcode
的类型为 DOUBLE。
当
updateFlag
实参为 TRUE (当您替换现有键值对时):如果指定的键在 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" | | | } | | +-----------------------+--------------------------------------------------------------+
转换 MAPs¶
要转换 MAPs,请使用以下函数:
处理结构化类型¶
以下部分介绍如何使用不同的 SQL 函数,以及使用结构化类型的对象设置运算符:
将 FLATTEN 函数用于结构化类型¶
您可以将结构化 ARRAYs、结构化 OBJECTs 和 MAPs 传递给 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。
对于 MAPs,返回的键和值的顺序是不确定的。
使用 PARSE_JSON 函数¶
请注意,PARSE_JSON 函数不返回结构化类型。
将结构化类型与集合运算符和 CASE 表达式一起使用¶
您可以在以下内容中使用结构化 ARRAYs、结构化 OBJECTs 和 MAPs:
对于集运算符,如果在不同的表达式中使用不同的类型(例如,如果一种类型是 ARRAY(NUMBER),另一种类型是 ARRAY(DOUBLE)),则一种类型将 强制转换 为另一种类型。
处理其他半结构化函数¶
以下函数不接受结构化 ARRAY、结构化 OBJECT 或 MAP 作为输入实参:
将结构化类型作为输入传递会导致错误。
使用驱动程序访问应用程序中的结构化类型¶
在使用驱动程序(例如 ODBC 或 JDBC 驱动程序、Snowflake Connector for Python 等)的应用程序中,会以半结构化类型的形式返回结构化类型值。例如:
结构化 ARRAY 列会以半结构化 ARRAY 的形式返回到客户端应用程序。
结构化 OBJECT 或 MAP 列会以半结构化 OBJECT 的形式返回到客户端应用程序。
将结构化类型与用户定义函数 (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.8
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”。该列不包括元素、键或值的类型。
要查看有关元素、键和值类型的信息,请使用以下视图:
有关结构化 ARRAYs 中的元素类型的信息,请查询 :doc:` INFORMATION_SCHEMA 中的 ELEMENT_TYPES 视图 </sql-reference/info-schema/element_types>` 或 :doc:` ACCOUNT_USAGE 中的 ELEMENT_TYPES 视图 </sql-reference/account-usage/element_types>`。
有关结构化 OBJECTs 和 MAPs 中的键和值的信息,请查询 :doc:` INFORMATION_SCHEMA 中的 FIELDS 视图 </sql-reference/info-schema/fields>` 或 :doc:` ACCOUNT_USAGE 中的 FIELDS 视图 </sql-reference/account-usage/fields>`。