カテゴリ:

テーブル関数

RESULT_SCAN

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

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

Tip

この関数の代わりに:doc:` パイプ演算子 </sql-reference/operators-flow>`(->>)、を使用して、以前のコマンドの結果を処理できます。

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

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()) と等価です。

この引数はオプションです。省略すると、デフォルトは :code:`RESULT_SCAN(-1)`であり、最新のコマンドの結果セットを返します。

使用上の注意

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

  • 元のクエリが :doc:`タスク </user-guide/tasks-intro>`を使用して実行された場合、特定のユーザーではなく、タスクを所有するロールがクエリをトリガーして実行しました。ユーザまたはタスクが同じロールで操作されている場合、 RESULT_SCAN を使用してクエリ結果にアクセスできます。

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

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

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

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

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

    Snowsight:

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

    • WorksheetsProjects`において、クエリ実行後 :ui:`Query Details のリンクを含める ID.

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

    SQL:

    次の関数のいずれかを呼び出します。

    • QUERY_HISTORY , QUERY_HISTORY_BY_* テーブル関数 。

    • LAST_QUERY_ID 関数(クエリが現在のセッションで実行された場合)。

      例:

      SELECT LAST_QUERY_ID(-2);
      
      Copy

      これは、 :doc:`/sql-reference/functions/last_query_id`の入力として RESULT_SCAN を使用することと同等です。

  • RESULT_SCAN が重複する列名を含むクエリ出力(たとえば、重複する列名を持つ2つのテーブルを 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 |
+-------+

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

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 コマンドを使用した例

DESCRIBE USER コマンドの結果を処理して、関心のある特定のフィールド、例えばユーザーの既定のロールを取得します。DESC USER コマンドからの出力列名は小文字で生成されたため、コマンドはクエリ内の列名を:ref:`二重引用符で囲まれた識別子<label-delimited_identifier>`で囲み、クエリの列名がスキャンしている出力の列名と一致することを確認します。

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

Process the result of a SHOW TABLES command to extract empty tables that are older than 21 days. The SHOW command generates lowercase column names, so the command quotes the names to use matching case:

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

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

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

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

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

CREATE TABLE employees (id INT);

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

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

INSERT INTO employees (id) VALUES (11);

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

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

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は、最初の列には元の名前を使用し、2番目の列には変更された一意の名前を割り当てます。名前を一意にするために、 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 |
+----+------+-------------+