- 类别:
RESULT_SCAN¶
返回前一条命令的结果集(在执行查询的 24 小时内),就好像结果是一个表一样。如果要处理以下任何一项的输出,这会非常有用:
您执行的 SHOW 或 DESC[RIBE] 命令。
您对元数据或账户使用情况信息(如 Snowflake Information Schema 或 Account Usage)执行的查询。
您 调用 的存储过程的结果。
命令/查询可以来自当前会话或任何其他会话,包括过去的会话,只要未超过 24 小时的期限即可。此期限不可调整。有关更多详细信息,请参阅 使用持久化查询结果。
- 另请参阅:
DESCRIBE RESULT (账户和会话 DDL)
语法¶
RESULT_SCAN ( { '<query_id>' | LAST_QUERY_ID() } )
实参¶
query_id
或LAST_QUERY_ID()
(过去 24 小时内在任意会话中)您执行的查询的 ID,或者 LAST_QUERY_ID 函数,该函数返回当前会话中的查询的 ID。
使用说明¶
如果原始查询是手动执行的,则只有执行原始查询的用户才能使用 RESULT_SCAN 函数处理查询的输出。即使具有 ACCOUNTADMIN 权限的用户也无法通过调用 RESULT_SCAN 访问其他用户的查询结果。
如果原始查询是通过 任务 执行的,则拥有该任务的角色(而非特定用户)将触发并运行查询。如果用户或任务使用相同的角色运行,则它们可以使用 RESULT_SCAN 来访问查询结果。
Snowflake 会将所有查询结果存储 24 小时。此函数仅返回在此时间段内执行的查询的结果。
结果集没有任何与其关联的元数据,因此处理大型结果的速度可能要比查询实际表的速度慢。
包含 RESULT_SCAN 的查询可能包括原始查询中没有的子句,例如筛选条件和 ORDER BY 子句。这允许您缩小或修改结果集的范围。
RESULT_SCAN 返回行的顺序不保证与原始查询返回行的顺序相同。您可以在 RESULT_SCAN 查询中包含 ORDER BY 子句,以指定特定顺序。
若要检索特定查询的 ID,请使用下列任一方法:
- Classic Console:
在以下任一位置,单击提供的链接以显示/复制 ID:
- SQL:
执行以下任一函数:
LAST_QUERY_ID 函数(如果查询在当前会话中执行)。
例如:
SELECT LAST_QUERY_ID(-2);
请注意,这等同于将 LAST_QUERY_ID 用作 RESULT_SCAN 的输入。
如果 RESULT_SCAN 处理包含重复列名的查询输出(例如,对具有重叠列名的两个表执行 JOINed 的查询),RESULT_SCAN 会使用修改后的名称(在原始名称后追加“_1”、“_2”等)引用重复的列。有关示例,请参阅下面的 示例 部分。
使用矢量化扫描器查询的 Parquet 文件中的时间戳有时会显示不同时区的时间。使用 CONVERT_TIMEZONE 函数将所有时间戳数据转换为标准时区。
排序规则详细信息¶
在 RESULT_SCAN
返回上一条语句的结果时,RESULT_SCAN
将保留其返回值的排序规则规范。
示例¶
简单示例¶
检索当前会话中最新查询结果内所有大于 1
的值:
SELECT $1 AS value FROM VALUES (1), (2), (3); +-------+ | VALUE | |-------| | 1 | | 2 | | 3 | +-------+ SELECT * FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())) WHERE value > 1; +-------+ | VALUE | |-------| | 2 | | 3 | +-------+
从当前会话中第二新的查询检索所有值:
SELECT * FROM table(RESULT_SCAN(LAST_QUERY_ID(-2)));
从当前会话中第一个查询检索所有值:
SELECT * FROM table(RESULT_SCAN(LAST_QUERY_ID(1)));
检索指定查询结果的 c2
列中的所有值:
SELECT c2 FROM TABLE(RESULT_SCAN('ce6687a4-331b-4a57-a061-02b2b0f0c17c'));
使用 DESCRIBE 和 SHOW 命令的示例¶
处理 DESCRIBE USER 命令的结果以检索感兴趣的特定字段,例如用户的默认角色。请注意,由于 DESC USER
命令的输出列名以小写形式生成,因此这些命令在查询中的列名周围使用分隔标识符表示法(双引号),以确保查询中的列名与扫描的输出中的列名相匹配。
DESC USER jessicajones; SELECT "property", "value" FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())) WHERE "property" = 'DEFAULT_ROLE' ;
处理 SHOW TABLES 命令的结果,以提取超过 21 天的空表。SHOW 命令生成小写形式的列名,因此该命令会引用名称并使用匹配的大小写:
SHOW TABLES; -- Show the tables that are more than 21 days old and that are empty -- (i.e. tables that I might have forgotten about). SELECT "database_name", "schema_name", "name" as "table_name", "rows", "created_on" FROM table(RESULT_SCAN(LAST_QUERY_ID())) WHERE "rows" = 0 AND "created_on" < DATEADD(day, -21, CURRENT_TIMESTAMP()) ORDER BY "created_on";
处理 SHOW TABLES 命令的结果,以按大小降序提取表。此示例还演示了如何使用 UDF,以人类可读性略胜一筹的格式显示表大小。
-- Show byte counts with suffixes such as "KB", "MB", and "GB". CREATE OR REPLACE FUNCTION NiceBytes(NUMBER_OF_BYTES INTEGER) RETURNS VARCHAR AS $$ CASE WHEN NUMBER_OF_BYTES < 1024 THEN NUMBER_OF_BYTES::VARCHAR WHEN NUMBER_OF_BYTES >= 1024 AND NUMBER_OF_BYTES < 1048576 THEN (NUMBER_OF_BYTES / 1024)::VARCHAR || 'KB' WHEN NUMBER_OF_BYTES >= 1048576 AND NUMBER_OF_BYTES < (POW(2, 30)) THEN (NUMBER_OF_BYTES / 1048576)::VARCHAR || 'MB' ELSE (NUMBER_OF_BYTES / POW(2, 30))::VARCHAR || 'GB' END $$ ; SHOW TABLES; -- Show all of my tables in descending order of size. SELECT "database_name", "schema_name", "name" as "table_name", NiceBytes("bytes") AS "size" FROM table(RESULT_SCAN(LAST_QUERY_ID())) ORDER BY "bytes" DESC;
使用存储过程的示例¶
存储过程调用会返回一个值。但此值不能直接处理,因为您不能在另一个语句中嵌入存储过程调用。若要解决此限制,可使用 RESULT_SCAN
来处理存储过程返回的值。下面是一个经过简化的示例:
首先创建一个返回“复杂”值(本例中为包含 JSON 兼容数据的字符串)的过程,该值可在从
CALL
返回后进行处理。CREATE OR REPLACE PROCEDURE return_JSON() RETURNS VARCHAR LANGUAGE JavaScript AS $$ return '{"keyA": "ValueA", "keyB": "ValueB"}'; $$ ;随后调用以下过程:
CALL return_JSON(); +--------------------------------------+ | RETURN_JSON | |--------------------------------------| | {"keyA": "ValueA", "keyB": "ValueB"} | +--------------------------------------+接下来的三个步骤从结果集中提取数据。
获取第一列(也是唯一的列):
SELECT $1 AS output_col FROM table(RESULT_SCAN(LAST_QUERY_ID())); +--------------------------------------+ | OUTPUT_COL | |--------------------------------------| | {"keyA": "ValueA", "keyB": "ValueB"} | +--------------------------------------+将输出从 VARCHAR 转换为 VARIANT:
SELECT PARSE_JSON(output_col) AS JSON_COL FROM table(RESULT_SCAN(LAST_QUERY_ID())); +---------------------+ | JSON_COL | |---------------------| | { | | "keyA": "ValueA", | | "keyB": "ValueB" | | } | +---------------------+提取与“keyB”键对应的值:
SELECT JSON_COL:keyB FROM table(RESULT_SCAN(LAST_QUERY_ID())); +---------------+ | JSON_COL:KEYB | |---------------| | "ValueB" | +---------------+
下面提供了一种更紧凑的方法,用于提取与上一个示例中相同的数据。此示例的语句较少,但可读性较差:
CALL return_JSON(); +--------------------------------------+ | RETURN_JSON | |--------------------------------------| | {"keyA": "ValueA", "keyB": "ValueB"} | +--------------------------------------+ SELECT JSON_COL:keyB FROM ( SELECT PARSE_JSON($1::VARIANT) AS JSON_COL FROM table(RESULT_SCAN(LAST_QUERY_ID())) ); +---------------+ | JSON_COL:KEYB | |---------------| | "ValueB" | +---------------+
CALL 的输出使用函数名称作为列名称。例如:
+--------------------------------------+ | RETURN_JSON | +--------------------------------------+ | {"keyA": "ValueA", "keyB": "ValueB"} | +--------------------------------------+
我们可以在查询中使用此列名。下面额外提供了一个精简版本,其中按名称而非列编号引用列:
CALL return_JSON(); +--------------------------------------+ | RETURN_JSON | |--------------------------------------| | {"keyA": "ValueA", "keyB": "ValueB"} | +--------------------------------------+ SELECT JSON_COL:keyB FROM ( SELECT PARSE_JSON(RETURN_JSON::VARIANT) AS JSON_COL FROM table(RESULT_SCAN(LAST_QUERY_ID())) ); +---------------+ | JSON_COL:KEYB | |---------------| | "ValueB" | +---------------+
具有重复列名称的示例¶
以下示例演示了在原始查询中存在重复列名时,RESULT_SCAN 实际上引用了备用列名的情况:
创建两个至少有一个列同名的表:
CREATE TABLE employees (id INT);CREATE TABLE dependents (id INT, employee_id INT);为两个表加载数据:
INSERT INTO employees (id) VALUES (11);INSERT INTO dependents (id, employee_id) VALUES (101, 11);现在执行一个查询,其输出将包含两个同名列:
SELECT * FROM employees INNER JOIN dependents ON dependents.employee_ID = employees.id ORDER BY employees.id, dependents.id ; +----+-----+-------------+ | ID | ID | EMPLOYEE_ID | |----+-----+-------------| | 11 | 101 | 11 | +----+-----+-------------+请注意,Snowsight 中的输出与上面显示的输出不同,因为 Snowsight 会自动处理重复列名。
现在调用 RESULT_SCAN 以处理该查询的结果。请注意,如果结果中具有同名的不同列,RESULT_SCAN 会为第一列使用原始名称,并为第二列分配唯一的经过修改的名称。为保证名称唯一,RESULT_SCAN 会为名称追加后缀“_<n>”,其中“<n>”是下一个可用数字,用于生成与前几列不同的名称。
SELECT id, id_1, employee_id FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())) WHERE id_1 = 101; +----+------+-------------+ | ID | ID_1 | EMPLOYEE_ID | |----+------+-------------| | 11 | 101 | 11 | +----+------+-------------+