结构化数据类型

结构化类型是 ARRAY、OBJECT 或 MAP,包含具有特定 Snowflake 数据类型 的元素或键值对。以下是结构化类型的示例:

  • INTEGER 元素的 ARRAY。

  • 包含 VARCHAR 和 NUMBER 键值对的 OBJECT。

  • 将 VARCHAR 键与 DOUBLE 值关联的 MAP。

您可以通过以下方式使用结构化类型:

  • 您可以在 Iceberg 表 中定义结构化类型列。

    Iceberg 数据类型 liststructmap 与 Snowflake 中的结构化 ARRAY、结构化 OBJECT 和 MAP 类型对应。

    结构化类型列最多支持 1000 个子列。

  • 从 Iceberg 表中的结构化类型列访问数据时,您可以使用结构化类型。

  • 您可以将 ARRAYOBJECTVARIANT 转换为相应的结构化类型(例如,将 ARRAY 转换为 INTEGER 元素的 ARRAY)。您还可以将结构化类型转换为半结构化类型。

备注

目前,Iceberg 表以外的表不支持结构化类型。不能将结构化类型的列添加到常规表中。

本主题介绍如何在 Snowflake 中使用结构化类型。

指定结构化类型

定义结构化类型列或将值转换为结构化类型时,请使用以下各部分中所述的语法:

指定结构化 ARRAY

若要指定结构化 ARRAY,请使用以下语法:

ARRAY( <element_type> [ NOT NULL ] )
Copy

其中:

  • 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;
Copy
+-------------------------------+-----------------------+
| 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 ] ]
    [ , ... ]
  ]
)
Copy

其中:

  • 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;
Copy
+----------------------------------------------------------------+------------------------+
| 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 ] )
Copy

其中:

  • 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;
Copy
+------------------------------------------------+
| MAP_EXAMPLE                                    |
|------------------------------------------------|
| map(VARCHAR(16777216), VARCHAR(16777216))[LOB] |
+------------------------------------------------+

在半结构化类型中使用结构化类型

您不能在 VARIANT、半结构化 OBJECT 或半结构化 ARRAY 中使用 MAP、结构化 OBJECT 或结构化 ARRAY。在以下情况下会发生错误:

  • OBJECT 常量 或 :ref:`ARRAY 常量 <label-array_constant>`中使用 MAP、结构化 OBJECT 或结构化 ARRAY。

  • 将 MAP、结构化 OBJECT 或结构化 ARRAY 传递给 OBJECT 或 ARRAY :doc:` 构造函数 </sql-reference/functions-semistructured>`。

转换结构化类型和半结构化类型

下表总结了将结构化 OBJECTs、结构化 ARRAYs 和 MAPs 转换 为半结构化 OBJECTs、ARRAYs 和 VARIANTs 的规则(反之亦然)。

源数据类型

目标数据类型

可转换

可强制转换

半结构化 ARRAY

结构化 ARRAY

半结构化 OBJECT

  • 结构化 OBJECT

  • MAP

半结构化 VARIANT

  • 结构化 ARRAY

  • 结构化 OBJECT

  • MAP

结构化 ARRAY

半结构化 ARRAY

  • 结构化 OBJECT

  • MAP

半结构化 OBJECT

  • 结构化 ARRAY

  • 结构化 OBJECT

  • MAP

半结构化 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;
Copy

或者:

SELECT
  SYSTEM$TYPEOF(
    [1,2,3]::ARRAY(NUMBER)
  ) AS array_cast_type,
  SYSTEM$TYPEOF(
    [1,2,3]::VARIANT::ARRAY(NUMBER)
  ) AS variant_cast_type;
Copy
+--------------------------+--------------------------+
| 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;
    
    Copy
    +---------------+-------------------------------+
    | 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 转换为包含 citystate 键值对(即 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;
Copy

或者:

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;
Copy
+--------------------------------------------------------------+--------------------------------------------------------------+
| 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;
Copy

或者:

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;
Copy
+------------------------------------------------+------------------------------------------------+
| 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_ARRAYTO_OBJECTTO_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;
    
    Copy
    +---------------------------------------+
    | [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 函数或使用 :: 运算符,从一种结构化类型转换为另一种结构化类型。您可以在以下结构化类型之间进行转换:

备注

结构化类型不支持 TRY_CAST。

如果无法将值从一种类型转换为另一种类型,则转换将失败。例如,尝试将 ARRAY(BOOLEAN) 转换为 ARRAY(DATE) 失败。

示例:从一种类型的 ARRAY 转换为另一种类型

以下示例将 ARRAY(NUMBER) 转换为 ARRAY(VARCHAR):

SELECT CAST(
  CAST([1,2,3] AS ARRAY(NUMBER))
  AS ARRAY(VARCHAR)
);
Copy

示例:在 OBJECT 中更改键值对顺序

以下示例更改了结构化 OBJECT 中键值对的顺序:

SELECT CAST(
  {'city': 'San Mateo','state': 'CA'}::OBJECT(city VARCHAR, state VARCHAR)
  AS OBJECT(state VARCHAR, city VARCHAR)
);
Copy

示例:更改 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);
Copy
+------------------------------------------------------------------------------+
| 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);
Copy
+------------------------------------------------------------------------------+
| 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);
Copy
SELECT OBJECT_CONSTRUCT(
  'name', 'abc',
  'created_date', '2020-01-18'::DATE
)::OBJECT(
  name VARCHAR,
  created_date DATE
);
Copy

有关详细信息,请参阅 将半结构化类型显式转换为结构化类型

备注

不能将结构化 ARRAYs、结构化 OBJECTs 或 MAPs 传递给这些函数。这样做将导致结构化类型被隐式转换为半结构化类型,这是不允许的(如 隐式转换值(强制) 中所述)。

使用 ARRAY 和 OBJECT 常量构造结构化 ARRAYs 和 OBJECTs

当您指定 ARRAY 常量 或 :ref:`OBJECT 常量 <label-object_constant>`时,您指定的是半结构化 ARRAY 或 OBJECT。

要构造结构化 ARRAY 或 OBJECT,必须显式转换表达式。例如:

SELECT [10, 20, 30]::ARRAY(NUMBER);
Copy
SELECT {
  'name': 'abc',
  'created_date': '2020-01-18'::DATE
}::OBJECT(
  name VARCHAR,
  created_date DATE
);
Copy

有关详细信息,请参阅 将半结构化类型显式转换为结构化类型

构造 MAP

要构造 MAP,请构造一个半结构化对象,并将 OBJECT 转换为 MAP。

例如,以下语句均生成 MAP {'city'->'San Mateo','state'->'CA'}

SELECT OBJECT_CONSTRUCT(
  'city', 'San Mateo',
  'state', 'CA'
)::MAP(
  VARCHAR,
  VARCHAR
);
Copy
SELECT {
  'city': 'San Mateo',
  'state': 'CA'
}::MAP(
  VARCHAR,
  VARCHAR
);
Copy

以下语句生成 MAP {-10->'CA',-20->'OR'}

SELECT {
  '-10': 'CA',
  '-20': 'OR'
}::MAP(
  NUMBER,
  VARCHAR
)
Copy

有关详细信息,请参阅 将半结构化 OBJECTs 和 VARIANTs 转换为 MAPs

在结构化类型中处理键、值和元素

以下各部分介绍如何在结构化类型中使用值和元素。

从结构化 OBJECT 中获取键列表

要获取结构化 OBJECT 中的键列表,请调用 OBJECT_KEYS 函数:

SELECT OBJECT_KEYS({'city':'San Mateo','state':'CA'}::OBJECT(city VARCHAR, state VARCHAR));
Copy

如果输入值是结构化的 OBJECT,则函数返回包含键的 ARRAY(VARCHAR)。如果输入值是半结构化 OBJECT,则函数返回 ARRAY。

获取 MAP 中的键列表

要获取 MAP 中的键列表,请调用 MAP_KEYS 函数:

SELECT MAP_KEYS({'my_key':'my_value'}::MAP(VARCHAR,VARCHAR));
Copy

访问结构化类型中的值和元素

您可以使用以下方法访问结构化 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;
Copy
+-------------------------------+-----------------------------+
| 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));
Copy

确定 MAP 的大小

要确定 MAP 的大小,请将 MAP 传递给 MAP_SIZE 函数:

SELECT MAP_SIZE({'my_key':'my_value'}::MAP(VARCHAR,VARCHAR));
Copy

在结构化 ARRAY 中查找元素

要确定结构化 ARRAY 中是否存在元素,请调用 ARRAY_CONTAINS 函数。例如:

SELECT ARRAY_CONTAINS(10, [1, 10, 100]::ARRAY(NUMBER));
Copy

要确定元素在结构化 ARRAY 中的位置,请调用 ARRAY_POSITION 函数。例如:

SELECT ARRAY_POSITION(10, [1, 10, 100]::ARRAY(NUMBER));
Copy

备注

对于这两个函数,请使用与 ARRAY 的类型 同类的类型

不要将元素的表达式转换为 VARIANT。

确定 MAP 是否包含键

若要确定 MAP 是否包含键,请调用 MAP_CONTAINS_KEY 函数:

例如:

SELECT MAP_CONTAINS_KEY('key_to_find', my_map);
Copy
SELECT MAP_CONTAINS_KEY(10, my_map);
Copy

比较对象

以下部分说明如何比较对象:

将结构化对象与半结构化对象进行比较

不能将结构化 ARRAY、结构化 OBJECT 或 MAP 与半结构化 ARRAY、OBJECT 或 VARIANT 进行比较。

将结构化对象与其他结构化对象进行比较

您可以比较两个相同类型的对象(例如两个结构化 ARRAYs、两个结构化 OBJECTs 或两个 MAPs)。

目前,支持使用以下比较运算符来比较结构化类型:

  • =

  • !=

  • <

  • <=

  • >=

  • >

比较两个结构化对象是否相等时,请注意以下事项:

  • 如果一种类型不能 强制转换 为另一种类型,则比较失败。

  • 当您比较具有数字键的 MAPs 时,这些键将作为数字(而不是 VARCHAR 值)进行比较。

使用 <, <=, >=, or > 比较两个结构化对象时,将按字母顺序比较结构化对象字段。例如,以下对象:

{'a':2,'b':1}::OBJECT(b INTEGER,a INTEGER)
Copy

大于:

{'a':1,'b':2}::OBJECT(b INTEGER,a INTEGER)
Copy

确定两个 ARRAYs 是否重叠

如果需要确定两个结构化的 ARRAYs 元素是否重叠,请调用 ARRAYS_OVERLAP 函数。例如:

SELECT ARRAYS_OVERLAP(numeric_array, other_numeric_array);
Copy

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 );
Copy

以下调用成功,因为 VARCHAR 可强制转换为 DOUBLE:

SELECT ARRAY_APPEND( [1,2]::ARRAY(DOUBLE), '3' );
Copy

以下调用失败,因为 DATE 无法强制转换为 NUMBER:

SELECT ARRAY_APPEND( [1,2]::ARRAY(NUMBER), '2022-02-02'::DATE );
Copy

可接受多个 ARRAYs 作为输入的函数

以下函数接受多个 ARRAYs 作为输入实参:

调用这些函数时,两个实参都必须是结构化 ARRAYs 或半结构化 ARRAYs。例如,以下调用失败,因为一个实参是结构化 ARRAY,而另一个实参是半结构化 ARRAY:

SELECT ARRAY_CAT( [1,2]::ARRAY(NUMBER), ['3','4'] );
Copy
SELECT ARRAY_CAT( [1,2], ['3','4']::ARRAY(VARCHAR) );
Copy

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);
Copy
+--------------------+-----------------------------------+
| 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) );
Copy

以下调用失败,因为 ARRAY(NUMBER) 与 ARRAY(VARCHAR) 不属于同类:

SELECT ARRAY_EXCEPT( [1,2]::ARRAY(NUMBER), ['2','3']::ARRAY(VARCHAR) );
Copy

转换结构化 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' );
    
    Copy
    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);
    
    Copy

    该函数会返回 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);
    
    Copy
    +------------+---------------------------+
    | 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
      );
      
      Copy
      093202 (23001): Function OBJECT_INSERT:
        expected structured object to not contain field city but it did.
      
    • 该函数返回一个结构化的 OBJECT。OBJECT 的类型包括新插入的键。例如,假设您添加具有 DOUBLE 值 94402zipcode 键:

      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);
      
      Copy

      该函数返回类型 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 的类型包括按指定顺序排列的键。

    例如,假设您按以下顺序选择 statecity 键:

    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);
    
    Copy

    该函数返回类型 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)));
    
    Copy
    +-------+----------------------+
    | 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)));
    
    Copy
    +--------+------------------------+----------+------------------------+
    | KEY    | SYSTEM$TYPEOF(KEY)     | VALUE    | SYSTEM$TYPEOF(VALUE)   |
    |--------+------------------------+----------+------------------------|
    | my_key | VARCHAR(16777216)[LOB] | my_value | VARCHAR(16777216)[LOB] |
    +--------+------------------------+----------+------------------------+
    
  • 否则,keyvalue 列的类型为 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) 和存储过程结合使用

SQLSnowflake ScriptingJavaPythonScala 中创建用户定义函数 (UDF)、用户定义表函数 (UDTF) 或存储过程时,可以在实参和返回值中使用结构化类型。例如:

CREATE OR REPLACE FUNCTION my_udf(
    location OBJECT(city VARCHAR, zipcode NUMBER, val ARRAY(BOOLEAN)))
  RETURNS VARCHAR
  AS
  $$
    ...
  $$;
Copy
CREATE OR REPLACE FUNCTION my_udtf(check BOOLEAN)
  RETURNS TABLE(col1 ARRAY(VARCHAR))
  AS
  $$
  ...
  $$;
Copy
CREATE OR REPLACE PROCEDURE my_procedure(values ARRAY(INTEGER))
  RETURNS ARRAY(INTEGER)
  LANGUAGE SQL
  AS
  $$
    ...
  $$;
Copy
CREATE OR REPLACE FUNCTION my_function(values ARRAY(INTEGER))
  RETURNS ARRAY(INTEGER)
  LANGUAGE PYTHON
  RUNTIME_VERSION=3.8
  AS
  $$
    ...
  $$;
Copy

备注

UDFs、UDTFs 和 JavaScript 中的存储过程尚不支持结构化类型。

查看有关结构化类型的信息

以下部分介绍可用于查看有关结构化类型的信息的视图和命令:

使用 SHOW COLUMNS 命令查看结构化类型信息

SHOW COLUMNS 命令的输出中,data_type 列包含有关元素、键和值类型的信息。

使用 DESCRIBE 和其他 SHOW 命令查看结构化类型信息

以下命令的输出包括有关结构化类型的信息:

例如,在 DESCRIBE RESULT 输出中,MAP (VARCHAR、VARCHAR)列的行包含 type 列中的以下值:

map(VARCHAR(16777216), VARCHAR(16777216))
Copy

ARRAY(NUMBER) 列的行包含 type 列中的以下值:

ARRAY(NUMBER(38,0))
Copy

查看有关数据库中使用的结构化类型的信息

对于结构化类型的列,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>`。

语言: 中文