CREATE EXTERNAL TABLE¶
在当前或指定的架构中创建新的 外部表 或替换现有的外部表。查询时,外部表会从指定外部暂存区中包含一个或多个文件的集合中读取数据,然后在单个 VARIANT 列中输出数据。
可以定义其他列,每个列定义由以下元素组成:名称、数据类型,以及(可选)列是否需要值 (NOT NULL) 或是否有任何参照完整性约束(例如主键、外键等)。有关详细信息,请参阅使用说明。
语法¶
-- Partitions computed from expressions
CREATE [ OR REPLACE ] EXTERNAL TABLE [IF NOT EXISTS]
<table_name>
( [ <col_name> <col_type> AS <expr> | <part_col_name> <col_type> AS <part_expr> ]
[ inlineConstraint ]
[ , <col_name> <col_type> AS <expr> | <part_col_name> <col_type> AS <part_expr> ... ]
[ , ... ] )
cloudProviderParams
[ PARTITION BY ( <part_col_name> [, <part_col_name> ... ] ) ]
[ WITH ] LOCATION = externalStage
[ REFRESH_ON_CREATE = { TRUE | FALSE } ]
[ AUTO_REFRESH = { TRUE | FALSE } ]
[ PATTERN = '<regex_pattern>' ]
FILE_FORMAT = ( { FORMAT_NAME = '<file_format_name>' | TYPE = { CSV | JSON | AVRO | ORC | PARQUET } [ formatTypeOptions ] } )
[ AWS_SNS_TOPIC = '<string>' ]
[ COPY GRANTS ]
[ COMMENT = '<string_literal>' ]
[ [ WITH ] ROW ACCESS POLICY <policy_name> ON (VALUE) ]
[ [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] ) ]
[ WITH CONTACT ( <purpose> = <contact_name> [ , <purpose> = <contact_name> ... ] ) ]
-- Partitions added and removed manually
CREATE [ OR REPLACE ] EXTERNAL TABLE [IF NOT EXISTS]
<table_name>
( [ <col_name> <col_type> AS <expr> | <part_col_name> <col_type> AS <part_expr> ]
[ inlineConstraint ]
[ , <col_name> <col_type> AS <expr> | <part_col_name> <col_type> AS <part_expr> ... ]
[ , ... ] )
cloudProviderParams
[ PARTITION BY ( <part_col_name> [, <part_col_name> ... ] ) ]
[ WITH ] LOCATION = externalStage
PARTITION_TYPE = USER_SPECIFIED
FILE_FORMAT = ( { FORMAT_NAME = '<file_format_name>' | TYPE = { CSV | JSON | AVRO | ORC | PARQUET } [ formatTypeOptions ] } )
[ COPY GRANTS ]
[ COMMENT = '<string_literal>' ]
[ [ WITH ] ROW ACCESS POLICY <policy_name> ON (VALUE) ]
[ [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] ) ]
[ WITH CONTACT ( <purpose> = <contact_name> [ , <purpose> = <contact_name> ... ] ) ]
-- Delta Lake
CREATE [ OR REPLACE ] EXTERNAL TABLE [IF NOT EXISTS]
<table_name>
( [ <col_name> <col_type> AS <expr> | <part_col_name> <col_type> AS <part_expr> ]
[ inlineConstraint ]
[ , <col_name> <col_type> AS <expr> | <part_col_name> <col_type> AS <part_expr> ... ]
[ , ... ] )
cloudProviderParams
[ PARTITION BY ( <part_col_name> [, <part_col_name> ... ] ) ]
[ WITH ] LOCATION = externalStage
PARTITION_TYPE = USER_SPECIFIED
FILE_FORMAT = ( { FORMAT_NAME = '<file_format_name>' | TYPE = { CSV | JSON | AVRO | ORC | PARQUET } [ formatTypeOptions ] } )
[ TABLE_FORMAT = DELTA ]
[ COPY GRANTS ]
[ COMMENT = '<string_literal>' ]
[ [ WITH ] ROW ACCESS POLICY <policy_name> ON (VALUE) ]
[ [ WITH ] TAG ( <tag_name> = '<tag_value>' [ , <tag_name> = '<tag_value>' , ... ] ) ]
[ WITH CONTACT ( <purpose> = <contact_name> [ , <purpose> = <contact_name> ... ] ) ]
其中:
inlineConstraint ::= [ NOT NULL ] [ CONSTRAINT <constraint_name> ] { UNIQUE | PRIMARY KEY | [ FOREIGN KEY ] REFERENCES <ref_table_name> [ ( <ref_col_name> [ , <ref_col_name> ] ) ] } [ <constraint_properties> ]有关其他内联约束的详细信息,请参阅 CREATE | ALTER TABLE ... CONSTRAINT。
cloudProviderParams (for Google Cloud Storage) ::= [ INTEGRATION = '<integration_name>' ] cloudProviderParams (for Microsoft Azure) ::= [ INTEGRATION = '<integration_name>' ]externalStage ::= @[<namespace>.]<ext_stage_name>[/<path>]formatTypeOptions ::= -- If FILE_FORMAT = ( TYPE = CSV ... ) COMPRESSION = AUTO | GZIP | BZ2 | BROTLI | ZSTD | DEFLATE | RAW_DEFLATE | NONE RECORD_DELIMITER = '<string>' | NONE FIELD_DELIMITER = '<string>' | NONE MULTI_LINE = TRUE | FALSE SKIP_HEADER = <integer> SKIP_BLANK_LINES = TRUE | FALSE ESCAPE_UNENCLOSED_FIELD = '<character>' | NONE TRIM_SPACE = TRUE | FALSE FIELD_OPTIONALLY_ENCLOSED_BY = '<character>' | NONE NULL_IF = ( '<string1>' [ , '<string2>' , ... ] ) EMPTY_FIELD_AS_NULL = TRUE | FALSE ENCODING = '<string>' -- If FILE_FORMAT = ( TYPE = JSON ... ) COMPRESSION = AUTO | GZIP | BZ2 | BROTLI | ZSTD | DEFLATE | RAW_DEFLATE | NONE MULTI_LINE = TRUE | FALSE ALLOW_DUPLICATE = TRUE | FALSE STRIP_OUTER_ARRAY = TRUE | FALSE STRIP_NULL_VALUES = TRUE | FALSE REPLACE_INVALID_CHARACTERS = TRUE | FALSE -- If FILE_FORMAT = ( TYPE = AVRO ... ) COMPRESSION = AUTO | GZIP | BZ2 | BROTLI | ZSTD | DEFLATE | RAW_DEFLATE | NONE REPLACE_INVALID_CHARACTERS = TRUE | FALSE -- If FILE_FORMAT = ( TYPE = ORC ... ) TRIM_SPACE = TRUE | FALSE REPLACE_INVALID_CHARACTERS = TRUE | FALSE NULL_IF = ( '<string>' [ , '<string>' ... ] -- If FILE_FORMAT = ( TYPE = PARQUET ... ) COMPRESSION = AUTO | SNAPPY | NONE BINARY_AS_TEXT = TRUE | FALSE REPLACE_INVALID_CHARACTERS = TRUE | FALSE
变体语法¶
CREATE EXTERNAL TABLE ...USING TEMPLATE¶
创建一个新的外部表,其列定义派生自一组包含半结构化数据的暂存文件。此功能支持 Apache Parquet、Apache Avro、ORC、JSON 和 CSV 文件。对 CSV 和 JSON 文件的支持目前为预览版。
CREATE [ OR REPLACE ] EXTERNAL TABLE <table_name> USING TEMPLATE <query> [ ... ] [ COPY GRANTS ]
备注
如果语句要替换同名的现有表,则从要替换的表中复制授权。如果没有该名称的现有表,则从要克隆的源表中复制授权。
有关 COPY GRANTS 的更多信息,请参阅本文档中的 COPY GRANTS。
必填参数¶
table_name指定表的标识符(即名称)的字符串;对于在其中创建表的架构必须是唯一的。
此外,标识符必须以字母字符开头,且不能包含空格或特殊字符,除非整个标识符字符串放在双引号内(例如,
"My object")。放在双引号内的标识符也区分大小写。有关更多信息,请参阅 标识符要求。
[ WITH ] LOCATION =指定用于暂存包含要读取数据的文件的外部暂存区和可选路径:
@[namespace.]ext_stage_name[/path]文件位于指定的命名外部暂存区。
既不支持字符串字面量也不支持 SQL 变量。
其中:
namespace是外部暂存区所在的数据库或架构,格式为database_name.schema_name或schema_name。如果数据库和架构当前正在用户会话中使用,则此参数为 选填;否则,为必填。path是云存储位置中文件的可选目录路径且区分大小写,用于限制要加载的文件组。不同的云存储服务也可以将路径称为 前缀 或 文件夹。外部表将此目录路径追加到暂存区定义中指定的任何路径。要查看暂存区定义,请运行
DESC STAGE stage_name并检查url属性值。例如,如果暂存 URL 包含路径a,外部表位置包含路径b,则外部表将读取暂存在stage/a/b中的文件。备注
为存储位置中的文件指定完整的 目录 路径,而不是部分路径(共享前缀)(例如,使用类似
@my_ext_stage/2025/的路径,而非@my_ext_stage/2025-*)。要筛选共享通用前缀的文件,请改用分区列。[ WITH ] LOCATION值 不能 引用特定的文件名。若要将外部表指向单个暂存文件,请使用PATTERN参数。
FILE_FORMAT = ( FORMAT_NAME = 'file_format_name' )或 .FILE_FORMAT = ( TYPE = CSV | JSON | AVRO | ORC | PARQUET [ ... ] )指定文件格式的字符串(常量):
FORMAT_NAME = file_format_name指定描述要扫描的暂存数据文件的现有命名文件格式。命名的文件格式决定数据文件的格式类型(例如 CSV、JSON)和其他任何格式选项。
TYPE = CSV | JSON | AVRO | ORC | PARQUET [ ... ]指定查询外部表时要扫描的暂存数据文件的格式类型。
如果指定了文件格式类型,则可以指定其他特定于格式的选项。有关更多信息,请参阅 :ref:`格式类型选项 <label-create_ext_table_formattypeoptions>`(本主题内容)。
默认:
TYPE = CSV。重要
当暂存区用于将数据加载到表中时,外部表 不 继承该暂存区定义中指定的 FILE_FORMAT 选项。要指定 FILE_FORMAT 选项,您 必须 在外部表定义中明确指定。Snowflake 对外部表定义中省略的任何 FILE_FORMAT 参数使用默认值。
备注
FORMAT_NAME和TYPE是互斥的;为了避免出现意外行为,在创建外部表时只应指定其中一个。
可选参数¶
col_name指定列标识符的字符串(即名称)。表标识符的所有要求也适用于列标识符。
有关更多信息,请参阅 标识符要求。
col_type指定列的数据类型的字符串(常量)。数据类型必须与列的
expr结果匹配。有关可为表列指定的数据类型的信息,请参阅 SQL 数据类型参考。
expr指定列的表达式的字符串。查询时,该列将返回从此表达式派生的结果。
外部表列是使用显式表达式定义的虚拟列。使用 VALUE 列或 METADATA$FILENAME 伪列将虚拟列添加为表达式:
- VALUE:
表示外部文件中单个行的 VARIANT 类型列。
- CSV:
VALUE 列将每一行构建为一个对象,其元素由列位置(即
{c1: <column_1_value>, c2: <column_2_value>, c3: <column_1_value> ...})标识。例如,添加一个名为
mycol的 VARCHAR,该列引用暂存 CSV 文件中的第一列:mycol varchar as (value:c1::varchar)
- 半结构化数据:
将元素名称和值放在双引号内。使用点表示法遍历 VALUE 列中的路径。
假设以下示例表示暂存文件中的单行半结构化数据:
{ "a":"1", "b": { "c":"2", "d":"3" } }
例如,添加一个名为
mycol的 VARCHAR 列,该列引用暂存文件中的嵌套重复c元素:mycol varchar as (value:"b"."c"::varchar)
- METADATA$FILENAME:
一个伪列,标识外部表中包含的每个暂存数据文件的名称,包括其在暂存区中的路径。有关示例,请参阅 `从分区列表达式自动添加的分区 `_(本主题内容)。
CONSTRAINT ...为表中的指定列定义内联或外联约束的字符串。
有关语法的详细信息,请参阅 CREATE | ALTER TABLE ... CONSTRAINT。有关约束条件的更多信息,请参阅 约束。
REFRESH_ON_CREATE = TRUE | FALSE指定是否在创建外部表后立即自动刷新一次外部表元数据。刷新外部表元数据会将元数据与指定暂存区路径中的当前数据文件列表同步。元数据需要执行此操作才能在 :emph:` 设置中指定的命名外部暂存区中注册任何
现有:samp:`[ WITH ] LOCATION =数据文件。TRUESnowflake 会在创建外部表元数据后自动刷新一次。
备注
如果指定位置包含接近 100 万或更多的文件,我们建议您设置
REFRESH_ON_CREATE = FALSE。创建外部表后,通过运行 ALTER EXTERNAL TABLE ...REFRESH 语句以增量方式刷新元数据,这些语句指定位置中的子路径(即刷新时要包含的文件子集),直到元数据包含该位置中的所有文件。FALSESnowflake 不会自动刷新外部表元数据。要注册暂存区中的任何现有数据文件,必须使 ALTER EXTERNAL TABLE ...REFRESH 手动刷新外部表元数据一次。
默认:
TRUEAUTO_REFRESH = TRUE | FALSE指定当 新的或更新的 数据文件在
[ WITH ] LOCATION =设置中指定的命名外部暂存区中可用时,Snowflake 是否应允许触发外部表元数据的自动刷新。备注
在对象所有者手动添加分区时(即,在
PARTITION_TYPE = USER_SPECIFIED时),已分区的外部表 不 支持将此参数设置为 TRUE。对于引用 S3 兼容存储(提供符合 S3 REST API 的 API 的存储应用程序或设备)中数据文件的外部表,不 支持将此参数设置为 TRUE。有关更多信息,请参阅 使用兼容 Amazon S3 的存储。
您必须通过运行 ALTER EXTERNAL TABLE ...REFRESH 命令手动刷新元数据。
必须 为存储位置配置事件通知,以便在可将新的或更新的数据读入外部表元数据时通知 Snowflake。有关更多信息,请参阅云存储服务的说明:
- Amazon S3:
- Google Cloud Storage:
- Microsoft Azure:
创建外部表时,其元数据会自动刷新一次,除非
REFRESH_ON_CREATE = FALSE。
TRUESnowflake 支持触发外部表元数据的自动刷新。
FALSESnowflake 不支持触发外部表元数据的自动刷新。您必须使用 ALTER EXTERNAL TABLE ... REFRESH 定期手动刷新外部表元数据,以使元数据与暂存区路径中的当前文件列表同步。
默认:
TRUE
PATTERN = 'regex_pattern'正则表达式模式字符串放在单引号内,可指定外部暂存区上要匹配的文件名和路径。
小技巧
为了获得最佳性能,请勿应用对大量文件进行筛选的模式。
AWS_SNS_TOPIC = 'string'仅在使用 Amazon Simple Notification Service (SNS) 为 Amazon S3 暂存区配置 AUTO_REFRESH 时需要。`指定 S3 桶中 ARN 主题的 Amazon Resource Name (SNS)。CREATE EXTERNAL TABLE 语句将 Amazon Simple Queue Service (SQS) 队列订阅至指定的 SNS 主题。通过 SNS 主题的事件通知会触发元数据刷新。有关更多信息,请参阅 :doc:/user-guide/tables-external-s3`。
TABLE_FORMAT = DELTA-
备注
此功能仍受支持,但将在未来的版本中被弃用。
请考虑改用 Apache Iceberg™ 表。Iceberg 表使用 外部卷 连接云存储中的 Delta 表文件。
有关更多信息,请参阅 Iceberg 表 和 CREATE ICEBERG TABLE(对象存储中的 Delta 文件)。您还可以参阅 将 Delta 外部表迁移到 Apache Iceberg™.
将外部表标识为引用云存储位置的 Delta Lake。支持 Amazon S3、Google Cloud Storage 或 Microsoft Azure 云存储中的 Delta Lake。
备注
所有账户都可以使用此 :doc:` 预览版功能 </release-notes/preview-features>`。
设置此参数后,外部表将扫描
[ WITH ] LOCATION位置中的 Delta Lake 事务日志文件。Delta 日志文件的名称为_delta_log/00000000000000000000.json和_delta_log/00000000000000000010.checkpoint.parquet等。刷新外部表的元数据时,Snowflake 将解析 Delta Lake 事务日志并确定哪些 Parquet 文件是当前文件。在后台,刷新会执行文件添加和移除操作,以保持外部表元数据同步。
备注
[ WITH ] LOCATION =中指定的外部暂存区和可选路径必须仅包含 单个 Delta Lake 表的数据文件和元数据。也就是说,指定的存储位置只能包含一个__delta_log目录。不保证云存储中 DDL 操作触发的事件通知顺序。因此,自动刷新功能不适用于引用 Delta Lake 文件的外部表。
REFRESH_ON_CREATE和AUTO_REFRESH都必须设置为 FALSE。定期运行 ALTER EXTERNAL TABLE ...REFRESH 语句来注册任何添加或移除的文件。
FILE_FORMAT值必须将 Parquet 指定为文件类型。为了获得最佳性能,我们建议为外部表定义分区列。
引用 Delta Lake 时,不支持以下参数:
AWS_SNS_TOPIC = 'string'PATTERN = 'regex_pattern'
COPY GRANTS指定当使用 CREATE OR REPLACE TABLE 变体重新创建外部表时,保留原始表的访问权限。该参数将现有表中 除 OWNERSHIP 以外的所有权限复制到新表中。默认情况下,运行 CREATE EXTERNAL TABLE 命令的角色拥有新的外部表。
备注
复制授权的操作在 CREATE EXTERNAL TABLE 命令中会以原子方式发生(即在同一事务中)。
COMMENT = 'string_literal'为外部表指定注释的字符串(字面量)。
默认:无值
ROW ACCESS POLICY <policy_name> ON (VALUE)指定要在表上设置的 行访问策略。
将行访问策略应用于外部表时指定 VALUE 列。
TAG ( tag_name = 'tag_value' [ , tag_name = 'tag_value' , ... ] )指定 标签 名称和标签字符串值。
标签值始终为字符串,标签值的最大字符数为 256。
有关在语句中指定标签的信息,请参阅 对象的标签配额。
WITH CONTACT ( purpose = contact [ , purpose = contact ...] )将新对象与一个或多个 联系人 关联。
分区参数¶
使用这些参数对外部表进行分区。
part_col_name col_type AS part_expr定义外部表中的一个或多个分区列。
分区列定义的格式会有所不同,具体取决于分区是从每个分区列中的表达式自动计算和添加分区,还是手动添加分区。
- 从表达式添加:
分区列必须计算为解析 METADATA$FILENAME 伪列中的路径或文件名信息的表达式。分区列通过修剪不需要扫描的数据文件(即对外部表进行分区)来优化查询性能。分区由与分区列表达式中的路径或文件名匹配的所有数据文件组成。
part_col_name指定分区列标识符(即名称)的字符串。表标识符的所有要求也适用于列标识符。
col_type指定列的数据类型的字符串(常量)。数据类型必须与列的
part_expr结果匹配。part_expr指定列的表达式的字符串。表达式必须包含 METADATA$FILENAME 伪列。
外部表目前支持分区表达式中的以下函数子集:
=、<>、>、>=、<、<=||+、--(负号)*AND、ORNOT
- 手动添加:
必需: 还要将
PARTITION_TYPE参数值设置为USER_SPECIFIED。分区列定义是解析内部(隐藏)METADATA$EXTERNAL_TABLE_PARTITION 列中的列元数据的表达式。从本质上讲,该定义仅定义列的数据类型。以下示例显示了分区列定义的格式:
part_col_name col_type AS ( PARSE_JSON (METADATA$EXTERNALTABLE_PARTITION):part_col_name::data_type )例如,假设列
col1、col2和col3分别包含 varchar、number 和 timestamp(时区)数据:col1 varchar as (parse_json(metadata$external_table_partition):col1::varchar), col2 number as (parse_json(metadata$external_table_partition):col2::number), col3 timestamp_tz as (parse_json(metadata$external_table_partition):col3::timestamp_tz)
为表定义任何分区列后,使用 PARTITION BY 子句标识这些列。
备注
用户指定的分区列名的最大长度为 32 个字符。
PARTITION_TYPE = USER_SPECIFIED将外部表的分区类型定义为 user-defined。外部表的所有者(即对外部表拥有 OWNERSHIP 权限的角色)必须通过运行 ALTER EXTERNAL TABLE ...ADD PARTITION 语句,手动将分区添加到外部元数据。
如果在评估分区列中的表达式时自动将分区添加到外部表元数据中,则 不要 设置此参数。
[ PARTITION BY ( part_col_name [, part_col_name ... ] ) ]指定要为外部表评估的任何分区列。
- 用途:
查询外部表时,在 WHERE 子句中包含一个或多个分区列,例如:
... WHERE part_col_name = 'filter_value'Snowflake 筛选分区列以限制要扫描的数据文件集。会扫描这些文件中的所有行。如果 WHERE 子句包含非分区列,则在筛选完数据文件 后 会对这些筛选器进行评估。
一种常见的做法是根据时间增量对数据文件进行分区;或者,如果数据文件是从多个源暂存的,则按数据源标识符和日期或时间戳进行分区。
云提供商参数 (cloudProviderParams)¶
Google Cloud Storage
INTEGRATION = integration_name指定用于使用 Google Pub/Sub 事件通知自动刷新外部表元数据的通知集成的名称。通知集成是一个 Snowflake 对象,它在 Snowflake 和第三方云消息队列服务之间提供一个接口。
此参数是启用外部表自动刷新操作所必需的。有关如何配置自动刷新功能的说明,请参阅 自动刷新 Google Cloud Storage 的外部表。
Microsoft Azure
INTEGRATION = integration_name指定用于使用 Azure 事件网格通知自动刷新外部表元数据的通知集成的名称。通知集成是一个 Snowflake 对象,它在 Snowflake 和第三方云消息队列服务之间提供一个接口。
此参数是启用外部表自动刷新操作所必需的。有关如何配置自动刷新功能的说明,请参阅 自动刷新 Azure Blob 存储的外部表。
格式类型选项 (formatTypeOptions)¶
格式类型选项用于 :doc:` 将数据加载到 </guides-overview-loading-data>` 中,以及 :doc:` 从 </user-guide/data-unload-overview>` 表中卸载数据。
根据指定的文件格式类型 (FILE_FORMAT = ( TYPE = ... )),可以包含以下一个或多个特定于格式的选项(用空格、逗号或换行符分隔):
TYPE = CSV¶
COMPRESSION = AUTO | GZIP | BZ2 | BROTLI | ZSTD | DEFLATE | RAW_DEFLATE | NONE为要查询的数据文件指定当前压缩算法的字符串(常量)。Snowflake 使用此选项来检测 已压缩 的数据文件是如何压缩的,以便提取文件中的压缩数据进行查询。
支持的值
备注
AUTO压缩算法会自动检测,但 Brotli 压缩文件除外(目前无法自动检测)。如果查询 Brotli 压缩文件,请显式使用
BROTLI而不是AUTO。GZIPBZ2BROTLI查询 Brotli 压缩文件时必须指定此值。
ZSTD支持 Zstandard v0.8(及更高版本)。
DEFLATE使用 Deflate 压缩的文件(带有 zlib 标头、RFC1950)。
RAW_DEFLATE使用 Raw Deflate 压缩的文件(无标头、RFC1951)。
NONE数据文件尚未压缩。
RECORD_DELIMITER = 'string' | NONE用于分隔输入文件中记录的一个或多个字符。接受常见的转义序列或以下单字节或多字节字符:
- 单字节字符:
八进制值(以
\\为前缀)或十六进制值(以0x或\x为前缀)。例如,对于由重音符号 (^) 字符分隔的记录,请指定八进制 (\\136) 或十六进制 (0x5e) 值。- 多字节字符:
十六进制值(前缀为
\x)。例如,对于由分 (¢) 字符分隔的记录,请指定十六进制 (\xC2\xA2) 值。RECORD_DELIMITER 或 FIELD_DELIMITER 分隔符不能是其他文件格式选项(例如
FIELD_DELIMITER = 'aa' RECORD_DELIMITER = 'aabb')的分隔符的子字符串。
指定的分隔符必须是有效的 UTF-8 字符,而不是随机的字节序列。另请注意,分隔符限制为最多 20 个字符。
也接受
NONE的值。默认值:换行符。请注意,“换行符”是合乎逻辑的,因而
\r\n可以理解为 Windows 平台上文件的换行符。FIELD_DELIMITER = 'string' | NONE一个或多个单字节或多字节字符,用于分隔输入文件中的字段。接受常见的转义序列或以下单字节或多字节字符:
- 单字节字符:
八进制值(以
\\为前缀)或十六进制值(以0x或\x为前缀)。例如,对于由重音符号 (^) 字符分隔的记录,请指定八进制 (\\136) 或十六进制 (0x5e) 值。- 多字节字符:
十六进制值(前缀为
\x)。例如,对于由分 (¢) 字符分隔的记录,请指定十六进制 (\xC2\xA2) 值。RECORD_DELIMITER 或 FIELD_DELIMITER 分隔符不能是其他文件格式选项(例如
FIELD_DELIMITER = 'aa' RECORD_DELIMITER = 'aabb')的分隔符的子字符串。备注
对于非 ASCII 字符,必须使用十六进制字节序列值来获取确定性行为。
指定的分隔符必须是有效的 UTF-8 字符,而不是随机的字节序列。另请注意,分隔符限制为最多 20 个字符。
也接受
NONE的值。默认值:逗号 (
,)MULTI_LINE = TRUE | FALSE布尔值,指定是否允许多行。
如果将 MULTI_LINE 设置为
FALSE,并且指定记录分隔符存在于 CSV 字段中,则包含该字段的记录将被解析为错误。默认:
TRUESKIP_HEADER = integer要跳过的文件开头的行数。
注意,SKIP_HEADER 不使用 RECORD_DELIMITER 或 FIELD_DELIMITER 值来决定标头行;相反,它会直接跳过文件中指定数量的以 CRLF(回车符、换行)分隔的行。然后,使用 RECORD_DELIMITER 和 FIELD_DELIMITER 确定要查询的数据行。
默认:
0SKIP_BLANK_LINES = TRUE | FALSE- 使用:
仅数据查询
- 定义:
布尔,指定是否跳过数据文件中遇到的任何空行;否则,空行将产生记录结束错误(默认行为)。
默认:
FALSEESCAPE_UNENCLOSED_FIELD = 'character' | NONE仅用作未封闭字段值的转义字符的单字节字符串。转义字符对字符序列中的后续字符调用替代解释。您可以使用 ESCAPE 字符将数据中
FIELD_DELIMITER或RECORD_DELIMITER字符的实例解释为字面量。转义字符还可用于对数据中自身的实例进行转义。接受常见的转义序列、八进制值或十六进制值。
仅指定未封闭字段的转义字符。
备注
默认值为
\\。如果数据文件中的行以反斜杠 (\) 字符结尾,则此字符将转义为RECORD_DELIMITER文件格式选项指定的换行符或回车符。因此,此行和下一行将作为单行数据进行处理。若要避免此问题,请将值设置为NONE。此文件格式选项仅支持单字节字符。请注意,UTF-8 字符编码将高阶 ASCII 字符表示为多字节字符。如果数据文件使用 UTF-8 字符集进行编码,则不能将高阶 ASCII 字符指定为选项值。
此外,如果指定高阶 ASCII 字符,建议将文件格式选项设置为
ENCODING = 'string'数据文件的字符编码,以确保正确解释该字符。
默认值:反斜杠 (
\\)TRIM_SPACE = TRUE | FALSE布尔,指定是否从字段中移除空格。
例如,如果您的外部数据库软件将字段放在引号中,但插入了前导空格,则 Snowflake 会读取前导空格而不是左引号字符作为字段的开头(即引号被解释为字段数据字符串的一部分)。将此选项设置为
TRUE可在查询数据时移除不需要的空格。再举一个例子,如果字符串两边的引号两边有前导空格或尾随空格,则可以使用此选项移除周围的空格,并使用
FIELD_OPTIONALLY_ENCLOSED_BY选项移除引号字符。请注意,引号 内 的任何空格都将保留。例如,假设FIELD_DELIMITER = '|'和FIELD_OPTIONALLY_ENCLOSED_BY = '"':|"Hello world"| /* returned as */ >Hello world< |" Hello world "| /* returned as */ > Hello world < | "Hello world" | /* returned as */ >Hello world<
请注意,此示例中的括号不返回;它们用于划分返回字符串的开头和结尾。
默认:
FALSEFIELD_OPTIONALLY_ENCLOSED_BY = 'character' | NONE用于包围字符串的字符。值可以是
NONE、单引号字符 (') 或双引号字符 (")。要使用单引号字符,请使用八进制或十六进制表示形式 (0x27) 或双单引号转义 ('')。默认:
NONENULL_IF = ( 'string1' [ , 'string2' , ... ] )用于与 SQL NULL 相互转换的字符串:
查询数据时,Snowflake 会将返回数据中的这些值替换为 SQL NULL。若要指定多个字符串,请将字符串列表放在括号中,并使用逗号分隔每个值。
请注意,无论数据类型如何,Snowflake 都会将该值的所有实例转换为 NULL。例如,如果
2指定为值,则转换为字符串或数字的所有2实例。例如:
NULL_IF = ('\N', 'NULL', 'NUL', '')请注意,此选项可以包含空字符串。
默认:
\N``(即 NULL,假设 :code:`ESCAPE_UNENCLOSED_FIELD` 值为 ``\\)EMPTY_FIELD_AS_NULL = TRUE | FALSE指定是否为输入文件中的空字段返回 SQL NULL,这些字段由两个连续的分隔符表示(例如
,,)。如果设置为
FALSE,Snowflake 会尝试将空字段转换为相应列类型。对于类型为 STRING 的列,将返回一个空字符串。对于其他列类型,查询将返回错误。默认:
TRUEENCODING = 'string'用于指定查询数据时源数据字符集的字符串(常量)。
字符 集
ENCODING值支持的语言
备注
Big5
BIG5繁体中文
EUC-JP
EUCJP日语
EUC-KR
EUCKR韩语
GB18030
GB18030中文
IBM420
IBM420阿拉伯语
IBM424
IBM424希伯来语
IBM949
IBM949韩语
ISO-2022-CN
ISO2022CN简体中文
ISO-2022-JP
ISO2022JP日语
ISO-2022-KR
ISO2022KR韩语
ISO-8859-1
ISO88591丹麦语、荷兰语、英语、法语、德语、意大利语、挪威语、葡萄牙语、瑞典语
ISO-8859-2
ISO88592捷克语、匈牙利语、波兰语、罗马尼亚语
ISO-8859-5
ISO88595俄语
ISO-8859-6
ISO88596阿拉伯语
ISO-8859-7
ISO88597希腊语
ISO-8859-8
ISO88598希伯来语
ISO-8859-9
ISO88599土耳其语
ISO-8859-15
ISO885915丹麦语、荷兰语、英语、法语、德语、意大利语、挪威语、葡萄牙语、瑞典语
与 ISO-8859-1 相同,但 8 个字符除外,包括欧元货币符号。
KOI8-R
KOI8R俄语
Shift_JIS
SHIFTJIS日语
UTF-8
UTF8所有语言
要从分隔文件(CSV、TSV 等)加载数据,默认为 UTF-8。. . 要从所有其他支持的文件格式(JSON、Avro 等)加载数据以及卸载数据,UTF-8 是唯一支持的字符集。
UTF-16
UTF16所有语言
UTF-16BE
UTF16BE所有语言
UTF-16LE
UTF16LE所有语言
UTF-32
UTF32所有语言
UTF-32BE
UTF32BE所有语言
UTF-32LE
UTF32LE所有语言
windows-874
WINDOWS874泰语
windows-949
WINDOWS949韩语
windows-1250
WINDOWS1250捷克语、匈牙利语、波兰语、罗马尼亚语
windows-1251
WINDOWS1251俄语
windows-1252
WINDOWS1252丹麦语、荷兰语、英语、法语、德语、意大利语、挪威语、葡萄牙语、瑞典语
windows-1253
WINDOWS1253希腊语
windows-1254
WINDOWS1254土耳其语
windows-1255
WINDOWS1255希伯来语
windows-1256
WINDOWS1256阿拉伯语
默认:
UTF8备注
Snowflake 将所有数据存储在 UTF-8 字符集中。数据将转换为 UTF-8。
TYPE = JSON¶
COMPRESSION = AUTO | GZIP | BZ2 | BROTLI | ZSTD | DEFLATE | RAW_DEFLATE | NONE为要返回的数据文件指定当前压缩算法的字符串(常量)。Snowflake 使用此选项来检测 已压缩 的数据文件是如何压缩的,以便提取文件中的压缩数据进行查询。
支持的值
备注
AUTO压缩算法会自动检测,但 Brotli 压缩文件除外(目前无法自动检测)。如果查询 Brotli 压缩文件,请显式使用
BROTLI而不是AUTO。GZIPBZ2BROTLIZSTDDEFLATE使用 Deflate 压缩的文件(带有 zlib 标头、RFC1950)。
RAW_DEFLATE使用 Raw Deflate 压缩的文件(无标头、RFC1951)。
NONE指示文件尚未压缩。
默认:
AUTOMULTI_LINE = TRUE | FALSE布尔值,指定是否允许多行。
如果将 MULTI_LINE 设置为
FALSE,并且 JSON 记录中存在新行,则包含新行的记录将被解析为错误。默认:
TRUEALLOW_DUPLICATE = TRUE | FALSE布尔,指定允许重复对象字段名称(仅保留最后一个)。
默认:
FALSESTRIP_OUTER_ARRAY = TRUE | FALSE布尔,指示 JSON 解析器移除外括号(即
[ ])。默认:
FALSESTRIP_NULL_VALUES = TRUE | FALSE布尔,指示 JSON 解析器移除包含
null值的对象字段或数组元素。例如,当设置为TRUE时,会发生以下变化:之前
之后
[null][][null,null,3][,,3]{"a":null,"b":null,"c":123}{"c":123}{"a":[1,null,2],"b":{"x":null,"y":88}}{"a":[1,,2],"b":{"y":88}}默认:
FALSEREPLACE_INVALID_CHARACTERS = TRUE | FALSE布尔,指定是否将无效的 UTF-8 字符替换为 Unicode 替换字符 (
�)。此选项执行一对一的字符替换。如果设置为
TRUE,Snowflake 会将无效的 UTF-8 字符替换为 Unicode 替换字符。如果设置为
FALSE,则加载操作在检测到无效的 UTF-8 字符编码时产生错误。默认:
FALSE
TYPE = AVRO¶
COMPRESSION = AUTO | GZIP | BZ2 | BROTLI | ZSTD | DEFLATE | RAW_DEFLATE | NONE为要查询的数据文件指定当前压缩算法的字符串(常量)。Snowflake 使用此选项来检测 已压缩 的数据文件是如何压缩的,以便提取文件中的压缩数据进行查询。
支持的值
备注
AUTO压缩算法会自动检测,但 Brotli 压缩文件除外(目前无法自动检测)。如果查询 Brotli 压缩文件,请显式使用
BROTLI而不是AUTO。GZIPBZ2BROTLIZSTDDEFLATE使用 Deflate 压缩的文件(带有 zlib 标头、RFC1950)。
RAW_DEFLATE使用 Raw Deflate 压缩的文件(无标头、RFC1951)。
NONE要查询的数据文件尚未压缩。
默认:
AUTO。
备注
我们建议您使用默认 AUTO 选项,因为它将确定文件和编解码器压缩。指定压缩选项是指对文件进行压缩,而不是对块(编解码器)进行压缩。
REPLACE_INVALID_CHARACTERS = TRUE | FALSE布尔,指定是否将无效的 UTF-8 字符替换为 Unicode 替换字符 (
�)。此选项执行一对一的字符替换。如果设置为
TRUE,Snowflake 会将无效的 UTF-8 字符替换为 Unicode 替换字符。如果设置为
FALSE,则加载操作在检测到无效的 UTF-8 字符编码时产生错误。默认:
FALSE
TYPE = ORC¶
TRIM_SPACE = TRUE | FALSE布尔,指定是否从字符串中移除前导和尾随空格。
例如,如果您的外部数据库软件将字段放在引号中,但插入了前导空格,则 Snowflake 会读取前导空格而不是左引号字符作为字段的开头(即引号被解释为字段数据字符串的一部分)。将此选项设置为
TRUE可移除不需要的空格。此文件格式选项仅适用于以下操作:
查询暂存 ORC 数据文件中的对象值。
使用 MATCH_BY_COLUMN_NAME 复制选项查询单独列中的 ORC 数据。
通过在 COPY 语句中指定查询来查询单独列中的 ORC 数据(即 COPY 转换)。
默认:
FALSEREPLACE_INVALID_CHARACTERS = TRUE | FALSE布尔,指定是否将无效的 UTF-8 字符替换为 Unicode 替换字符 (
�)。此选项执行一对一的字符替换。如果设置为
TRUE,Snowflake 会将无效的 UTF-8 字符替换为 Unicode 替换字符。如果设置为
FALSE,则加载操作在检测到无效的 UTF-8 字符编码时产生错误。默认:
FALSENULL_IF = ( 'string1' [ , 'string2' , ... ] )用于与 SQL NULL 相互转换的字符串。Snowflake 用 SQL NULL 替换数据源中的这些字符串。若要指定多个字符串,请将字符串列表放在括号中,并使用逗号分隔每个值。
请注意,无论数据类型如何,Snowflake 都会将该值的所有实例转换为 NULL。例如,如果
2指定为值,则转换为字符串或数字的所有2实例。例如:
NULL_IF = ('\N', 'NULL', 'NUL', '')请注意,此选项可以包含空字符串。
在暂存 ORC 数据文件中查询对象值时,会应用此文件格式选项。
默认:``N``(即 NULL)
TYPE = PARQUET¶
COMPRESSION = AUTO | SNAPPY | NONE指定 Parquet 文件中列的当前压缩算法的字符串(常量)。
支持的值
备注
AUTO自动检测压缩算法。支持以下压缩算法:Brotli、gzip、Lempel-Ziv-Oberhumer (LZO)、LZ4、Snappy 或 Zstandard v0.8(及更高版本)。
SNAPPYNONE数据文件尚未压缩。
默认:
AUTOBINARY_AS_TEXT = TRUE | FALSE布尔,指定是否将未定义逻辑数据类型的列解释为 UTF-8 文本。当设置为
FALSE时,Snowflake 会将这些列解释为二进制数据。默认:
TRUE备注
Snowflake 建议您将 BINARY_AS_TEXT 设置为 FALSE 以避免任何潜在的转换问题。
REPLACE_INVALID_CHARACTERS = TRUE | FALSE布尔,指定是否将无效的 UTF-8 字符替换为 Unicode 替换字符 (
�)。此选项执行一对一的字符替换。如果设置为
TRUE,Snowflake 会将无效的 UTF-8 字符替换为 Unicode 替换字符。如果设置为
FALSE,则加载操作在检测到无效的 UTF-8 字符编码时产生错误。默认:
FALSE
访问控制要求¶
权限 |
对象 |
备注 |
|---|---|---|
CREATE EXTERNAL TABLE |
架构 |
|
CREATE STAGE |
架构 |
如果创建新暂存区,则为必填项。 |
USAGE |
暂存区 |
如果引用现有暂存区,则为必填项。 |
USAGE |
文件格式 |
要对架构中的任何对象执行操作,需要对父数据库和架构的 USAGE 权限。请注意,如果某个角色获授某个架构的任意权限,该角色便能够解析该架构。例如,若某角色被授予 CREATE 权限,则可以在该架构上创建对象,而无需 同时 被授予该架构的 USAGE 权限。
有关创建具有指定权限集的自定义角色的说明,请参阅 创建自定义角色。
使用说明¶
外部表仅支持外部(S3、Azure 或 GCS)暂存区;不支持内部 (Snowflake) 暂存区。
外部表不支持存储版本控制(S3 版本控制、Google Cloud Storage 中的对象版本控制或 Azure Storage 的版本控制)。
您不能访问存档云存储类别中保存的数据,这些数据需要恢复后才能检索。例如,这些存档存储类别包括 Amazon S3 Glacier Flexible Retrieval 或 Glacier Deep Archive 存储类别,或者 Microsoft Azure Archive Storage。
Snowflake 不会对外部表强制实施完整性约束。特别是,与普通表不同,Snowflake 不强制执行 NOT NULL 约束。
外部表包括以下元数据列:
METADATA$FILENAME:外部表中包含的每个暂存数据文件的名称。包括暂存区中数据文件的路径。
METADATA$FILE_ROW_NUMBER:暂存数据文件中每条记录的行号。
外部表不支持以下项:
群集密钥
克隆
XML 格式的数据
Time Travel
有关将外部表和策略结合使用的信息,请参阅以下主题:
使用
OR REPLACE等效于在现有外部表上使用 DROP EXTERNAL TABLE,然后创建具有相同名称的新外部表。CREATE OR REPLACE <object> 语句是原子的。也就是说,当对象被替换时,旧对象将被删除,新对象将在单个事务中创建。
这意味着与 CREATE OR REPLACE EXTERNAL TABLE 操作并发的任何查询都使用旧的或新的外部表版本。
关于元数据:
注意
客户应确保在使用 Snowflake 服务时,不会将个人数据(用户对象除外)、敏感数据、出口管制数据或其他受监管数据作为元数据输入。有关更多信息,请参阅 Snowflake 中的元数据字段。
创建外部表时,将行访问策略添加到外部表中,使用 POLICY_CONTEXT 函数模拟受行访问策略保护的外部表上的查询。
SELECT
*始终会返回 VALUE 列,其中所有常规或半结构化数据都投射到变体行。OR REPLACE和IF NOT EXISTS子句互斥。它们不能同时用于同一条语句中。
示例¶
从分区列表达式自动添加的分区¶
创建一个外部表,其中包含从分区列定义中的表达式计算的分区。
在以下示例的步骤 2 中,数据文件按以下结构在云存储中组织:logs/YYYY/MM/DD/HH24。例如:
logs/2018/08/05/0524/logs/2018/08/27/1408/
为存储数据文件的存储位置创建一个名为
s1的外部暂存区。有关更多信息,请参阅 CREATE STAGE。暂存区定义包括路径
/files/logs/:Amazon S3
CREATE STAGE s1 URL='s3://mybucket/files/logs/' ... ;
Google Cloud Storage
CREATE STAGE s1 URL='gcs://mybucket/files/logs/' ... ;
Microsoft Azure
CREATE STAGE s1 URL='azure://mycontainer/files/logs/' ... ;
查询暂存数据中的 METADATA$FILENAME 伪列,然后使用结果来开发分区列:
SELECT metadata$filename FROM @s1/; +----------------------------------------+ | METADATA$FILENAME | |----------------------------------------| | files/logs/2018/08/05/0524/log.parquet | | files/logs/2018/08/27/1408/log.parquet | +----------------------------------------+
创建已分区的外部表。
分区列
date_part使用 TO_DATE、DATE 将 METADATA$FILENAME 伪列中的YYYY/MM/DD转换为日期。SQL 命令还将 Parquet 指定为文件格式类型。Amazon S3 和 Microsoft Azure 云存储的外部表包括由来自相应云消息传递服务的事件通知触发时自动刷新元数据所需的参数:
Amazon S3
CREATE EXTERNAL TABLE et1( date_part date AS TO_DATE(SPLIT_PART(metadata$filename, '/', 3) || '/' || SPLIT_PART(metadata$filename, '/', 4) || '/' || SPLIT_PART(metadata$filename, '/', 5), 'YYYY/MM/DD'), timestamp bigint AS (value:timestamp::bigint), col2 varchar AS (value:col2::varchar)) PARTITION BY (date_part) LOCATION=@s1/logs/ AUTO_REFRESH = true FILE_FORMAT = (TYPE = PARQUET) AWS_SNS_TOPIC = 'arn:aws:sns:us-west-2:001234567890:s3_mybucket';
Google Cloud Storage
CREATE EXTERNAL TABLE et1( date_part date AS TO_DATE(SPLIT_PART(metadata$filename, '/', 3) || '/' || SPLIT_PART(metadata$filename, '/', 4) || '/' || SPLIT_PART(metadata$filename, '/', 5), 'YYYY/MM/DD'), timestamp bigint AS (value:timestamp::bigint), col2 varchar AS (value:col2::varchar)) PARTITION BY (date_part) LOCATION=@s1/logs/ AUTO_REFRESH = true FILE_FORMAT = (TYPE = PARQUET);
Microsoft Azure
CREATE EXTERNAL TABLE et1( date_part date AS TO_DATE(SPLIT_PART(metadata$filename, '/', 3) || '/' || SPLIT_PART(metadata$filename, '/', 4) || '/' || SPLIT_PART(metadata$filename, '/', 5), 'YYYY/MM/DD'), timestamp bigint AS (value:timestamp::bigint), col2 varchar AS (value:col2::varchar)) PARTITION BY (date_part) INTEGRATION = 'MY_INT' LOCATION=@s1/logs/ AUTO_REFRESH = true FILE_FORMAT = (TYPE = PARQUET);
刷新外部表元数据:
ALTER EXTERNAL TABLE et1 REFRESH;
查询外部表时,使用 WHERE 子句按分区列筛选数据。Snowflake 仅扫描指定分区中符合筛选条件的文件:
SELECT timestamp, col2 FROM et1 WHERE date_part = to_date('08/05/2018');
手动添加的分区¶
使用用户定义的分区创建外部表(即分区由外部表所有者手动添加)。
为存储数据文件的存储位置创建一个名为
s2的外部暂存区:暂存区定义包括路径
/files/logs/:Amazon S3
CREATE STAGE s2 URL='s3://mybucket/files/logs/' ... ;
Google Cloud Storage
CREATE STAGE s2 URL='gcs://mybucket/files/logs/' ... ;
Microsoft Azure
CREATE STAGE s2 URL='azure://mycontainer/files/logs/' ... ;
创建已分区的外部表。外部表包括三个具有不同数据类型的分区列。
以下规则适用:
分区表达式中的列名区分大小写。
分区列名 必须 为大写,除非列名放在双引号内。或者,在 SQL 表达式中使用 GET_IGNORE_CASE 而不是区分大小写的
:字符。如果列名放在双引号内(例如 "Column1"),则分区列名也必须放在双引号内,并且与列名完全匹配。
三种云存储服务(Amazon S3、Google Cloud Storage 和 Microsoft Azure)的语法相同,因为外部表元数据不会刷新:
create external table et2( col1 date as (parse_json(metadata$external_table_partition):COL1::date), col2 varchar as (parse_json(metadata$external_table_partition):COL2::varchar), col3 number as (parse_json(metadata$external_table_partition):COL3::number)) partition by (col1,col2,col3) location=@s2/logs/ partition_type = user_specified file_format = (type = parquet);
为分区列添加分区:
ALTER EXTERNAL TABLE et2 ADD PARTITION(col1='2022-01-24', col2='a', col3='12') LOCATION '2022/01';
Snowflake 将分区添加到外部表的元数据中。该操作还会将指定位置的任何新数据文件添加到元数据中:
+---------------------------------------+----------------+-------------------------------+ | file | status | description | +---------------------------------------+----------------+-------------------------------+ | mycontainer/files/logs/2022/01/24.csv | REGISTERED_NEW | File registered successfully. | | mycontainer/files/logs/2022/01/25.csv | REGISTERED_NEW | File registered successfully. | +---------------------------------------+----------------+-------------------------------+
查询外部表时,使用 WHERE 子句按分区列筛选数据。此示例按记录在暂存数据文件中的存储顺序返回记录:
SELECT col1, col2, col3 FROM et1 WHERE col1 = TO_DATE('2022-01-24') AND col2 = 'a' ORDER BY METADATA$FILE_ROW_NUMBER;
外部表上的物化视图¶
基于 从分区列表达式自动添加的分区 中创建的外部表中列的子查询创建物化视图示例:
CREATE MATERIALIZED VIEW et1_mv
AS
SELECT col2 FROM et1;
有关此 SQL 命令的一般语法、用法说明和更多示例,请参阅 CREATE MATERIALIZED VIEW。
使用检测到的列定义创建的外部表¶
创建一个外部表,其中的列定义源自一组包含 Avro、Parquet 或 ORC 数据的暂存文件。
备注
语句中引用的 mystage 暂存区和 my_parquet_format 文件格式必须已存在。一组文件必须已暂存在暂存区定义中引用的云存储位置中。
以下示例以 INFER_SCHEMA 主题中的一个示例为基础:
CREATE EXTERNAL TABLE mytable USING TEMPLATE ( SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*)) FROM TABLE( INFER_SCHEMA( LOCATION=>'@mystage', FILE_FORMAT=>'my_parquet_format' ) ) ) LOCATION=@mystage FILE_FORMAT=my_parquet_format AUTO_REFRESH=false;
如果返回的结果大于 16 MB,则在 ARRAY_AGG(OBJECT_CONSTRUCT()) 中使用 * 可能会导致错误。避免对较大的结果集使用 *,而是仅将所需的列 COLUMN NAME、TYPE 和 NULLABLE 用于查询,如以下示例所示。使用 WITHIN GROUP (ORDER BY order_id) 时可以包含可选列 ORDER_ID。
CREATE EXTERNAL TABLE mytable USING TEMPLATE ( SELECT ARRAY_AGG(OBJECT_CONSTRUCT('COLUMN_NAME',COLUMN_NAME, 'TYPE',TYPE, 'NULLABLE', NULLABLE, 'EXPRESSION',EXPRESSION)) FROM TABLE( INFER_SCHEMA( LOCATION=>'@mystage', FILE_FORMAT=>'my_parquet_format' ) ) ) LOCATION=@mystage FILE_FORMAT=my_parquet_format AUTO_REFRESH=false;