Postgresで9.3 以降、これはLATERAL
で解決するのが最適です。 参加:
SELECT *
FROM actors a
JOIN movies_actors ma on a.actor_id = ma.movie_id
LEFT JOIN LATERAL hi_lo(a.actor_id, length(a.name), ma.movie_id) x ON true
LIMIT 10;
関数の繰り返し評価を回避します(出力の列ごとに、いずれかの方法で入力行ごとに関数を呼び出す必要があります)。
LEFT JOIN LATERAL ... ON true
関数が行を返さない場合に左側から行を削除しないようにするには:
- LATERALとPostgreSQLのサブクエリの違いは何ですか?
コメントのフォローアップ:
関数呼び出しによって生成された展開された列のみ
SELECT x.* -- that's all!
FROM actors a
JOIN movies_actors ma on a.actor_id = ma.movie_id
LEFT JOIN LATERAL hi_lo(a.actor_id, length(a.name), ma.movie_id) x ON true
LIMIT 10;
ただし、他の列は気にしないため、次のように簡略化できます。
SELECT x.*
FROM actors a
JOIN movies_actors ma on a.actor_id = ma.movie_id
, hi_lo(a.actor_id, length(a.name), ma.movie_id) x
LIMIT 10;
これは暗黙のCROSS JOIN LATERAL
。関数が実際に「行なし」を返すことがある場合、結果は異なる可能性があります。行のNULL値は取得されず、それらの行は削除されるだけです。LIMIT
もう数えません。
古いバージョンの場合 (または一般的に)正しい構文で複合型を分解することもできます:
SELECT *, (hi_lo(a.actor_id, length(a.name), ma.movie_id)).* -- note extra parentheses!
FROM actors a
JOIN movies_actors ma on a.actor_id = ma.movie_id
LIMIT 10;
欠点は、Postgresクエリプランナーの弱点により、関数が関数出力の列ごとに1回評価されることです。呼び出しをサブクエリまたはCTEに移動し、外側のSELECT
の行タイプを分解することをお勧めします 。いいね:
SELECT actor_id, movie_id, (x).* -- explicit column names for the rest
FROM (
SELECT *, hi_lo(a.actor_id, length(a.name), ma.movie_id) AS x
FROM actors a
JOIN movies_actors ma on a.actor_id = ma.movie_id
LIMIT 10
) sub;
ただし、個々の列に名前を付ける必要があり、SELECT *
で逃げることはできません。 結果の行タイプに冗長性がある場合を除きます。関連:
- 複合結果を展開するときに、同じ関数を複数回呼び出すことは避けてください
- SQLクエリで(func())。*構文を使用して複数の関数の評価を回避するにはどうすればよいですか?