とは LATERAL
参加しますか?
この機能はPostgreSQL9.3で導入されました。マニュアル:
FROM
に表示されるサブクエリ キーワードLATERAL
を前に付けることができます 。これにより、先行するFROM
によって提供される列を参照できます。 アイテム。 (LATERAL
なし 、各サブクエリは独立して評価されるため、他のFROM
を相互参照することはできません。 アイテム。)
FROM
に表示されるテーブル関数 キーワードLATERAL
を前に付けることもできます 、ただし、関数の場合、キーワードはオプションです。関数の引数には、前にあるFROM
によって提供される列への参照を含めることができます。 いずれにせよアイテム。
基本的なコード例がそこにあります。
より相関のように サブクエリ
LATERAL
結合は、LATERAL
の右側にある式において、単純なサブクエリではなく、相関サブクエリに似ています。 結合は、その左側の行ごとに1回評価されます-相関のように サブクエリ-プレーンなサブクエリ(テーブル式)が一度評価される間 それだけ。 (ただし、クエリプランナーには、どちらの場合もパフォーマンスを最適化する方法があります。)
両方のコード例を並べた関連回答で、同じ問題を解決します:
- GROUP BYクエリを最適化して、ユーザーごとに最新の行を取得します
複数の列を返す場合 、LATERAL
通常、結合はより単純で、よりクリーンで、より高速です。
また、相関サブクエリに相当するものは、 LEFT JOIN LATERAL ... ON true
であることを忘れないでください。 :
- 配列引数を使用して集合を返す関数を複数回呼び出す
サブクエリで実行できないこと
LATERAL
結合は可能ですが、(相関する)サブクエリは(簡単に)できません。相関サブクエリは、裸の関数呼び出し(複数の行を返す場合に結果の行を乗算する)を除いて、単一の値のみを返すことができ、複数の列や複数の行を返すことはできません。ただし、特定のセットを返す関数でさえ、FROM
でのみ許可されます。 句。 unnest()
のように Postgres9.4以降では複数のパラメータを使用します。マニュアル:
これは
FROM
でのみ許可されています 条項;
したがって、これは機能しますが、(簡単に)サブクエリに置き換えることはできません:
CREATE TABLE tbl (a1 int[], a2 int[]);
SELECT * FROM tbl, unnest(a1, a2) u(elem1, elem2); -- implicit LATERAL
カンマ(,
)FROM
句はCROSS JOIN
の短い表記です 。LATERAL
テーブル関数では自動的に想定されます。UNNEST( array_expression [, ... ] )
の特殊なケースについて :
- FROM句でのみ許可されるset-returning-functionをどのように宣言しますか?
SELECT
のセットリターン関数 リスト
unnest()
のような集合を返す関数を使用することもできます SELECT
で 直接リストします。これは、同じSELECT
内に複数のそのような関数があるという驚くべき動作を示していました。 Postgres9.6までのリスト。しかし、ついにPostgres 10でサニタイズされ、現在は有効な代替手段です(標準SQLでなくても)。参照:
- SELECT句で複数のセットを返す関数に期待される動作は何ですか?
上記の例に基づいて構築:
SELECT *, unnest(a1) AS elem1, unnest(a2) AS elem2
FROM tbl;
比較:
ここに9.6ページのdbfiddle
10ページのdbfiddleはこちら
誤った情報を明確にする
マニュアル:
INNER
の場合 およびOUTER
結合タイプの場合、結合条件を指定する必要があります。つまり、NATURAL
の1つだけを指定する必要があります。 、ON
join_condition 、またはUSING
( join_column [、...])。意味については、以下を参照してください。
CROSS JOIN
の場合 、これらの句はいずれも表示できません。
したがって、これら2つのクエリは有効です(特に有用ではない場合でも):
SELECT *
FROM tbl t
LEFT JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t ON TRUE;
SELECT *
FROM tbl t, LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t;
これはそうではありませんが:
SELECT *
FROM tbl t
LEFT JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t;
Andomarのコード例が正しいのはそのためです(CROSS JOIN
結合条件は必要ありません)、Attilaのは そうではありませんでした。