カテゴリ:

クエリ構文

LATERAL

FROM 句では、 LATERAL キーワードを使用すると、インラインビューでそのインラインビューの前にあるテーブル式から列を参照できます。

A lateral join behaves more like a correlated subquery than a typical join. A lateral join behaves as if the server executed a loop similar to the following:

for each row in left_hand_table LHT:
    execute right_hand_subquery RHS using the values from the current row in the LHT
Copy

Unlike the output of a non-lateral join, the output from a lateral join includes only the rows generated from the inline view. There is no need for an explicit ON clause to join rows from the left-hand side to the right-hand side; the relationship is already established because the inline view references columns from the left-hand table expression.

側方結合の使用 もご参照ください。

LATERAL を使用するタイミング

LATERALは、以下のようなユースケースに役立つツールです。

  • ネストされたデータのテーブル関数のチェーン :配列内の配列をフラット化する必要がある場合や、ネストされたJSONの複数のレベルをナビゲートする必要がある場合、後続の各テーブル関数呼び出しは、前の呼び出しの出力を参照する必要があります。ラテラル結合はこれを可能にします。

  • 行固有の引数を使用してテーブル関数を呼び出す :テーブル関数(UDTFなど)は、左側のテーブルから行ごとに異なる入力値を受け取る必要があります。

単一レベルの配列をフラット化するなどの単純なケースでは、ラテラル結合なしで TABLE(FLATTEN(...)) を使用すると同じ結果が生成されます。ラテラル結合は、インラインビューがFROM句の前の式からのみ取得できる列を参照する必要がある場合にのみ必要です。

構文

SELECT ...
  FROM <left_hand_table_expression>, LATERAL ( <inline_view> )
...
Copy

パラメーター

left_hand_table_expression

これは、次のような行のソースです。

  • テーブル。

  • ビュー。

  • サブクエリ。

  • テーブル関数。

  • 以前の結合の結果。

inline_view

inline_view は次のいずれかです。

  • インラインビュー: ステートメント内で定義され、ステートメントの期間のみ有効なビュー。

  • サブクエリ。

  • テーブル関数: FLATTEN などの組み込みテーブル関数またはユーザー定義のテーブル関数(UDTF)のいずれか。

inline_view はプレーンテーブル参照にはできません。WHERE句またはテーブル関数呼び出しを使用するサブクエリなど、左側のテーブル式の値に基づいて行を処理またはフィルターできる式でなければなりません。

使用上の注意

  • キーワード LATERAL の後のインラインビューは、インラインビュー自体および FROM 句のインラインビューの左側のテーブルからのみ列を参照できます。

    SELECT *
      FROM table_reference_me, LATERAL (...), table_do_not_reference_me ...
    
    Copy
  • Although the inline view typically references one or more columns from the left_hand_table_expression, it is not required to do so.

  • INNER JOIN 構文がコンマまたはキーワード「INNER JOIN」を使用できるように、ラテラル結合でもコンマまたはキーワード INNER JOIN を使用できます。例:

    FROM departments AS d INNER JOIN LATERAL (...)
    
    Copy
  • ON、USING、またはNATURAL JOIN句は、以下で指定できません。

    • ラテラルテーブル関数(SQL UDTF以外)

    • テーブル関数への外部ラテラル結合(SQL UDTF以外)

    For details, see the usage notes in the JOIN topic.

例: FLATTEN テーブル関数でのラテラル結合の使用 および WHERE 句での FLATTEN を使用した結果のフィルター処理 もご参照ください)

次の例では、これらのテーブルを使用します。

CREATE TABLE departments (department_id INTEGER, name VARCHAR);
CREATE TABLE employees (employee_ID INTEGER, last_name VARCHAR,
  department_ID INTEGER, project_names ARRAY);

INSERT INTO departments (department_ID, name) VALUES
  (1, 'Engineering'),
  (2, 'Support');
INSERT INTO employees (employee_ID, last_name, department_ID) VALUES
  (101, 'Richards', 1),
  (102, 'Paulson',  1),
  (103, 'Johnson',  2);
Copy

以下のクエリは、サブクエリを含むラテラル結合です。

SELECT *
  FROM departments AS d,
    LATERAL (SELECT * FROM employees AS e WHERE e.department_ID = d.department_ID) AS iv2
  ORDER BY employee_ID;
Copy
+---------------+-------------+-------------+-----------+---------------+---------------+
| DEPARTMENT_ID | NAME        | EMPLOYEE_ID | LAST_NAME | DEPARTMENT_ID | PROJECT_NAMES |
|---------------+-------------+-------------+-----------+---------------+---------------|
|             1 | Engineering |         101 | Richards  |             1 | NULL          |
|             1 | Engineering |         102 | Paulson   |             1 | NULL          |
|             2 | Support     |         103 | Johnson   |             2 | NULL          |
+---------------+-------------+-------------+-----------+---------------+---------------+

次の SQL ステートメントは同等で、同じ出力を生成します。FROM 句のコンマの代わりに INNER JOIN というキーワードが使われています。

SELECT *
  FROM departments AS d INNER JOIN
    LATERAL (SELECT * FROM employees AS e WHERE e.department_ID = d.department_ID) AS iv2
  ORDER BY employee_ID;
Copy

ネストされたデータ用にLATERAL FLATTENをチェーンする

LATERALは、複数の FLATTEN 呼び出しをチェーンして、ネスト化されたデータ構造にアクセスする必要がある場合に必要です。次の例では、2番目のFLATTENは、最初のFLATTENの出力を参照する必要があります。これはLATERALでしかできません。

CREATE OR REPLACE TABLE persons AS
  SELECT column1 AS id, PARSE_JSON(column2) AS c
    FROM VALUES
      (12712555,
       '{ "name": { "first": "John", "last": "Smith" },
          "contact": [{ "business": [
            { "type": "phone", "content": "555-1234" },
            { "type": "email", "content": "j.smith@example.com" }
          ]}]}'),
      (98127771,
       '{ "name": { "first": "Jane", "last": "Doe" },
          "contact": [{ "business": [
            { "type": "phone", "content": "555-1236" },
            { "type": "email", "content": "j.doe@example.com" }
          ]}]}');
Copy

次のクエリは2つのLATERAL FLATTEN呼び出しを使用します。最初の呼び出しは contact 配列をフラット化し、2番目は各連絡先内で business 配列をフラット化します。2番目のFLATTEN呼び出しは、 f.value を参照します。これは、最初のFLATTEN呼び出しの出力から得られます。

SELECT id,
    f1.value:type::STRING AS contact_type,
    f1.value:content::STRING AS contact_details
  FROM persons p,
    LATERAL FLATTEN(INPUT => p.c, PATH => 'contact') f,
    LATERAL FLATTEN(INPUT => f.value:business) f1;
Copy
+----------+--------------+---------------------+
|       ID | CONTACT_TYPE | CONTACT_DETAILS     |
|----------+--------------+---------------------|
| 12712555 | phone        | 555-1234            |
| 12712555 | email        | j.smith@example.com |
| 98127771 | phone        | 555-1236            |
| 98127771 | email        | j.doe@example.com   |
+----------+--------------+---------------------+

このクエリは、LATERALなしでは記述できません。なぜなら、2番目のFLATTEN呼び出しは、最初のFLATTEN呼び出しの出力に依存するからです。

LATERALと他のアプローチとの比較

次のテーブルは、他のアプローチと比較してLATERALを使用するタイミングをまとめたものです。

ユースケース

推奨

単一レベルの配列をフラット化する

LATERALなしの TABLE(FLATTEN(...)) は同じように動作します。LATERALはオプションです。

ネストされた配列をフラット化する(配列内の配列)

チェーンFLATTEN呼び出しにはLATERALが必要です。

現在の行に基づいて別のテーブルから行をフィルターする

SELECTリストの相関サブクエリまたはLATERALで動作します。LATERALは複数の行と列を返すことができます。SELECTの相関サブクエリはこれを実行できません。

行固有の入力でテーブル関数を呼び出す

LATERALは、テーブル関数が行ごとに異なる引数を受け取ることを許可します。