回答:
LATERAL
(Postgresの9.3またはそれ以降)は、より似ている参加相関サブクエリではなく、普通サブクエリ。Andomarが指摘したように、LATERAL
結合の右側の関数またはサブクエリは、相関サブクエリと同様に、その左側の各行に対して1回評価する必要がありますが、プレーンサブクエリ(テーブル式)は1回だけ評価されます。(ただし、クエリプランナーには、どちらか一方のパフォーマンスを最適化する方法があります。)
この関連する回答には、同じ問題を解決する両方のコード例があります。
複数の列を返す場合、LATERAL
結合は通常、よりシンプルでクリーンで高速です。
また、相関サブクエリに相当するものはLEFT JOIN LATERAL ... ON true
次のとおりです。
LATERAL
これは、ここで回答に入れるものよりも信頼性があります。
ありますことを、物事LATERAL
を行うことができます参加するには、しかし、(相関)サブクエリは(簡単に)することはできません。相関サブクエリは、複数の列や複数の行ではなく、単一の値のみを返すことができます。ただし、裸の関数呼び出し(複数の行を返す場合に結果行を乗算する)を除きます。ただし、特定のセットを返す関数でさえ、FROM
句でのみ許可されます。unnest()
Postgres 9.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 [, ... ] )
:
SELECT
リスト内のセットを返す関数リストのようunnest()
にSELECT
直接セットを返す関数を使用することもできます。これは、SELECT
Postgres 9.6まで、同じリストにこのような関数が複数あるという驚くべき動作を示していました。しかし、それは最終的にPostgres 10でサニタイズされ、現在では有効な代替手段です(標準SQLでなくても)。見る:
上記の例に基づいて構築:
SELECT *, unnest(a1) AS elem1, unnest(a2) AS elem2
FROM tbl;
比較:
PG 9.6用dbfiddle ここでは、
PG 10用dbfiddle こちら
以下のために
INNER
とOUTER
参加の種類、状態、すなわち正確の一つに指定されている必要があり参加しNATURAL
、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
結合条件を必要としない)とアッティラの@ IS無効でした。
LATERAL
サブクエリでウィンドウ関数を示す別の回答を追加しました:gis.stackexchange.com/a/230070/7244
非結合lateral
とlateral
結合の違いは、左側のテーブルの行を見ることができるかどうかにあります。例えば:
select *
from table1 t1
cross join lateral
(
select *
from t2
where t1.col1 = t2.col1 -- Only allowed because of lateral
) sub
この「外向き」は、サブクエリを複数回評価する必要があることを意味します。結局のところ、t1.col1
多くの値を想定できます。
対照的に、非lateral
結合後のサブクエリは1回だけ評価できます。
select *
from table1 t1
cross join
(
select *
from t2
where t2.col1 = 42 -- No reference to outer query
) sub
なしlateral
で必要とされるように、内部クエリは外部クエリにまったく依存しません。lateral
クエリは、一例であるcorrelated
ため、クエリ自体の外側行との関係を、クエリ。
select * from table1 left join t2 using (col1)
比較しますか?/ on条件を使用した結合が不十分であるかどうかは不明であり、ラテラルを使用する方が理にかなっています。
まず、ラテラルとクロス適用は同じものです。したがって、クロスアプライについてもお読みください。これはSQL Serverに古くから実装されていたため、ラテラルよりもさらに詳しい情報が得られます。
第二に、私の理解によれば、ラテラルを使用する代わりにサブクエリを使用してできないことはありません。だが:
次のクエリを検討してください。
Select A.*
, (Select B.Column1 from B where B.Fk1 = A.PK and Limit 1)
, (Select B.Column2 from B where B.Fk1 = A.PK and Limit 1)
FROM A
この状態でラテラルを使用できます。
Select A.*
, x.Column1
, x.Column2
FROM A LEFT JOIN LATERAL (
Select B.Column1,B.Column2,B.Fk1 from B Limit 1
) x ON X.Fk1 = A.PK
このクエリでは、limit句のため、通常の結合を使用できません。単純な結合条件がない場合は、ラテラルまたはクロスアプライを使用できます。
ラテラルまたはクロスアプライの使用法は他にもありますが、これは私が見つけた最も一般的なものです。
lateral
代わりに使用するのかと思いますapply
。おそらく、Microsoftは構文の特許を取得していますか?
lateral
はSQL標準に含まれていますが、そうでapply
はありません。
LEFT JOIN
は結合条件が必要です。それを作るON TRUE
あなたが何らかの形で制限したい場合を除きます。
cross join
またはon
条件を使用しない限り、エラーが発生します
誰も指摘していないことの1つはLATERAL
、クエリを使用して、選択したすべての行にユーザー定義関数を適用できることです。
例えば:
CREATE OR REPLACE FUNCTION delete_company(companyId varchar(255))
RETURNS void AS $$
BEGIN
DELETE FROM company_settings WHERE "company_id"=company_id;
DELETE FROM users WHERE "company_id"=companyId;
DELETE FROM companies WHERE id=companyId;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM (
SELECT id, name, created_at FROM companies WHERE created_at < '2018-01-01'
) c, LATERAL delete_company(c.id);
これが、PostgreSQLでこの種のことを行う方法を知る唯一の方法です。
apply
同じであるlateral
SQL標準から)