类别:

表函数

RESULT_SCAN

返回前一条命令的结果集(在运行查询的 24 小时内),就好像结果是一个表一样。如果要处理以下任何一项操作的输出,此函数会非常有用:

命令或查询可以来自当前会话或任何其他会话,包括过去的会话,只要未超过 24 小时的期限即可。此期限不可调整。有关更多信息,请参阅 使用持久化查询结果

小技巧

您可以使用 管道运算符 (->>) 而不是此函数来处理先前命令的结果。

另请参阅:

DESCRIBE RESULT (账户和会话 DDL)

语法

RESULT_SCAN ( [ { '<query_id>' | <query_index>  | LAST_QUERY_ID() } ] )
Copy

实参

'query_id' query_index LAST_QUERY_ID()

过去 24 小时内您在任意会话中运行的查询的规范,当前会话中查询的整型索引,或 LAST_QUERY_ID 函数,该函数返回当前会话中查询的 ID。

Snowflake 查询 IDs 是类似 01b71944-0001-b181-0000-0129032279f6 的唯一字符串。

查询索引相对于当前会话中的第一个查询(如果为正)或最近的查询(如果为负)。例如,RESULT_SCAN(-1) 相当于 RESULT_SCAN(LAST_QUERY_ID())

此实参是可选的。如果省略,则默认值为 RESULT_SCAN(-1),它返回最近命令的结果集。

使用说明

  • 如果原始查询是手动运行的,则只有运行原始查询的用户才能使用 RESULT_SCAN 函数处理查询的输出。即使具有 RESULT_SCAN 权限的用户也无法通过调用 ACCOUNTADMIN 访问其他用户的查询结果。

  • 如果原始查询是通过 任务 运行的,则负责该任务的角色(而非特定用户)触发并运行查询。如果用户或任务使用相同的角色运行,则它们可以使用 RESULT_SCAN 来访问查询结果。

  • Snowflake 会将所有查询结果存储 24 小时。此函数仅返回在此时间段内运行的查询的结果。

  • 结果集没有任何与其关联的元数据,因此处理大型结果的速度可能要比查询实际表的速度慢。

  • 包含 RESULT_SCAN 的查询可能包括原始查询中没有的子句,例如筛选条件和 ORDER BY 子句。您可以使用这些子句来缩小或修改结果集的范围。

  • RESULT_SCAN 返回行的顺序不保证与原始查询返回行的顺序相同。您可以在 ORDER 查询中包含 BY RESULT_SCAN 子句,以指定特定顺序。

  • 若要检索特定查询的 ID,请使用下列任一方法:

    Snowsight:

    在以下任一位置,单击提供的链接以显示或复制 ID:

    • Worksheets 中的 Projects 下,运行查询后,Query Details 包含 ID 的链接。

    • Query History 中的 Monitoring 下,每个查询都包含链接形式的 ID。

    SQL:

    调用以下任一函数:

  • 如果 RESULT_SCAN 处理包含重复列名的查询输出(例如,联接具有重叠列名的两个表的查询),RESULT_SCAN 会使用修改后的名称(在原始名称后追加 _1_2 等)引用重复的列。有关示例,请参阅下面的 示例 部分。

  • 通过使用矢量化扫描器查询的 Parquet 文件中的时间戳有时会显示不同时区的时间。使用 CONVERT_TIMEZONE 函数将所有时间戳数据转换为标准时区。

排序规则详细信息

RESULT_SCAN 返回上一条语句的结果时,RESULT_SCAN 将保留其返回值的排序规则规范。

示例

以下示例使用 RESULT_SCAN 函数。

简单示例

检索当前会话中最新查询结果内所有大于 1 的值:

SELECT $1 AS value FROM VALUES (1), (2), (3);
Copy
+-------+
| VALUE |
|-------|
|     1 |
|     2 |
|     3 |
+-------+
SELECT * FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())) WHERE value > 1;
Copy
+-------+
| VALUE |
|-------|
|     2 |
|     3 |
+-------+

从当前会话中第二新的查询检索所有值:

SELECT * FROM TABLE(RESULT_SCAN(LAST_QUERY_ID(-2)));
Copy

从当前会话中第一个查询检索所有值:

SELECT * FROM TABLE(RESULT_SCAN(LAST_QUERY_ID(1)));
Copy

检索指定查询结果的 c2 列中的所有值:

SELECT c2 FROM TABLE(RESULT_SCAN('ce6687a4-331b-4a57-a061-02b2b0f0c17c'));
Copy

使用 DESCRIBE 和 SHOW 命令的示例

Process the result of a DESCRIBE USER command to retrieve particular fields of interest, such as the user's default role. Because the output column names from the DESC USER command were generated in lowercase, the commands use double-quoted identifiers for the column names in the query to ensure that the column names in the query match the column names in the output that was scanned.

DESC USER jessicajones;
SELECT "property", "value" FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
  WHERE "property" = 'DEFAULT_ROLE';
Copy

处理 SHOW TABLES 命令的结果,以提取超过 21 天的空表。SHOW 命令生成小写形式的列名,因此该命令会引用名称以使用匹配的大小写:

SHOW TABLES;
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";
Copy

处理 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;
Copy

使用存储过程的示例

存储过程调用会返回一个值。但此值不能直接处理,因为您不能在另一个语句中嵌入存储过程调用。若要解决此限制,可使用 RESULT_SCAN 来处理存储过程返回的值。下面是一个经过简化的示例:

首先创建一个返回“复杂”值(本例中为包含 JSON 兼容数据的字符串)的过程,该值可在从 CALL 返回后进行处理。

CREATE OR REPLACE PROCEDURE return_json()
  RETURNS VARCHAR
  LANGUAGE JavaScript
  AS
  $$
    return '{"keyA": "ValueA", "keyB": "ValueB"}';
  $$
  ;
Copy

调用过程:

CALL return_json();
Copy
+--------------------------------------+
| RETURN_JSON                          |
|--------------------------------------|
| {"keyA": "ValueA", "keyB": "ValueB"} |
+--------------------------------------+

接下来的三个步骤从结果集中提取数据。

获取第一列(也是唯一的列):

SELECT $1 AS output_col FROM table(RESULT_SCAN(LAST_QUERY_ID()));
Copy
+--------------------------------------+
| OUTPUT_COL                           |
|--------------------------------------|
| {"keyA": "ValueA", "keyB": "ValueB"} |
+--------------------------------------+

将输出从 VARCHAR 值转换为 VARIANT 值:

SELECT PARSE_JSON(output_col) AS json_col FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()));
Copy
+---------------------+
| JSON_COL            |
|---------------------|
| {                   |
|   "keyA": "ValueA", |
|   "keyB": "ValueB"  |
| }                   |
+---------------------+

提取与键 keyB 对应的值:

SELECT json_col:keyB FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()));
Copy
+---------------+
| JSON_COL:KEYB |
|---------------|
| "ValueB"      |
+---------------+

以下示例显示了一种更精简的方法,用于提取与上一个示例中相同的数据。此示例的语句较少,但可读性较差:

CALL return_json();
Copy
+--------------------------------------+
| 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()))
      );
Copy
+---------------+
| JSON_COL:KEYB |
|---------------|
| "ValueB"      |
+---------------+

CALL 的输出使用函数名称作为列名称。您可以在查询中使用该列名。以下示例显示了另一个精简版本,其中按名称而非列编号引用列:

CALL return_json();
Copy
+--------------------------------------+
| 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()))
       );
Copy
+---------------+
| JSON_COL:KEYB |
|---------------|
| "ValueB"      |
+---------------+

具有重复列名称的示例

以下示例演示了在原始查询中存在重复列名时,RESULT_SCAN 实际上引用了备用列名的情况:

创建两个至少有一个列同名的表:

CREATE TABLE employees (id INT);

CREATE TABLE dependents (id INT, employee_id INT);
Copy

为两个表加载数据:

INSERT INTO employees (id) VALUES (11);

INSERT INTO dependents (id, employee_id) VALUES (101, 11);
Copy

现在运行一个查询,其输出将包含两个同名列:

SELECT *
  FROM employees INNER JOIN dependents
    ON dependents.employee_ID = employees.id
  ORDER BY employees.id, dependents.id;
Copy
+----+-----+-------------+
| ID |  ID | EMPLOYEE_ID |
|----+-----+-------------|
| 11 | 101 |          11 |
+----+-----+-------------+

现在调用 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;
Copy
+----+------+-------------+
| ID | ID_1 | EMPLOYEE_ID |
|----+------+-------------|
| 11 |  101 |          11 |
+----+------+-------------+
语言: 中文