カテゴリ:

テーブル関数

RESULT_SCAN

結果がテーブルであるかのように、以前のコマンドの結果セット(クエリを実行した24時間以内)を返します。これは、次のいずれかからの出力を処理する場合に特に便利です。

24時間が経過していない限り、コマンド/クエリは現在のセッションまたは過去のセッションを含む他のセッションから取得できます。この時間は調整できません。詳細については、 永続的なクエリ結果の使用 をご参照ください。

こちらもご参照ください:

DESCRIBE RESULT (アカウントとセッション DDL)

構文

RESULT_SCAN ( { '<query_id>'  | LAST_QUERY_ID() } )

引数

クエリID または LAST_QUERY_ID()

実行したクエリのID(任意のセッションの過去24時間以内)または LAST_QUERY_ID 過去のクエリID 関数です。現在のセッション内のクエリの ID を返します。

使用上の注意

  • Snowflakeは、すべてのクエリ結果を24時間保存します。この関数は、この期間内に実行されたクエリの結果のみを返します。

  • 結果セットにはメタデータが関連付けられていないため、大きな結果の処理は、実際のテーブルをクエリする場合よりも遅くなる可能性があります。

  • RESULT_SCAN を含むクエリには、元のクエリにはなかったフィルターや ORDER BY句などの句を含めることができます。これにより、結果セットの絞り込みや変更ができます。

  • RESULT_SCAN では、元のクエリが行を返したのと同じ順序で行を返すことが保証されていません。特定の順序を指定するために、 RESULT_SCAN クエリに ORDER BY 句を含めることができます。

  • 特定のクエリの ID を取得するには、次のいずれかの方法を使用します。

    ウェブインターフェイス

    次のいずれかの場所で、提供されたリンクをクリックして IDを表示/コピーします。

    • Worksheets Worksheet tab では、クエリの実行後、結果に IDのリンクが含まれます。

    • History History tab では、各クエリに ID がリンクとして含まれています。

    SQL

    次の関数のいずれかを実行します。

  • 元のクエリを実行したユーザーのみが RESULT_SCAN 関数を使用して、そのクエリの結果を後処理できます。 ACCOUNTADMIN 権限を持つ別のユーザーであっても、 RESULT_SCANを呼び出して別のユーザーのクエリの結果にアクセスすることはできません。

  • RESULT_SCAN が重複する列名を含むクエリ出力(たとえば、重複する列名を持つ2つのテーブルを JOINed するクエリ)を処理する場合、 RESULT_SCAN は変更された名前を持つ重複した列を参照し、元の名前に「_1」、「_2」などを追加します。例については、以下の セクションをご参照ください。

照合の詳細

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

現在のセッションで2番目に新しいクエリからすべての値を取得します。

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 FLOAT)
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("rows") AS "size"
    FROM table(RESULT_SCAN(LAST_QUERY_ID()))
    ORDER BY "size" DESC;

ストアドプロシージャの使用例

ストアドプロシージャコールは値を返します。ただし、ストアドプロシージャコールを別のステートメントに埋め込むことはできないため、この値を直接処理することはできません。この制限を回避するには、 RESULT_SCAN を使用して、ストアドプロシージャによって返される値を処理します。簡単な例を以下に示します。

最初に、 CALL から返された後に処理できる「複雑な」値(この場合は JSON互換データを含む文字列)を返すプロシージャを作成します。

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"} |
+--------------------------------------+

次の3つの手順では、結果セットからデータを抽出します。

最初の(そして唯一の)列を取得します。

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 が代替列名を効果的に参照することを示しています。

同じ名前の列が少なくとも1つある2つのテーブルを作成します。

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

2つのテーブルにデータをロードします。

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

次に、出力に同じ名前の2つの列が含まれるクエリを実行します。

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

次に、 RESULT_SCAN を呼び出して、そのクエリの結果を処理します。同じ名前の列の場合、 RESULT_SCAN は元の名前の最初の列を認識しますが、変更された名前(列名に「_1」が追加された)の2番目の列を認識します。

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