I Postgres 9.3 eller senere løses dette bedst med en LATERAL
deltage:
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;
Undgår gentagen evaluering af funktionen (for hver kolonne i outputtet - funktionen skal kaldes for hver inputrække på begge måder).LEFT JOIN LATERAL ... ON true
for at undgå at tabe rækker fra venstre side, hvis funktionen ikke returnerer nogen række:
- Hvad er forskellen mellem LATERAL og en underforespørgsel i PostgreSQL?
Opfølgning i din kommentar:
kun de udvidede kolonner produceret af funktionskaldet
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;
Men da du er ligeglad med andre kolonner, kan du forenkle til:
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;
Hvilket er en implicit CROSS JOIN LATERAL
. Hvis funktionen rent faktisk kan returnere "ingen række" lejlighedsvis, kan resultatet være anderledes:vi får ikke NULL-værdier for rækkerne, disse rækker er blot elimineret - og LIMIT
tæller dem ikke mere.
I ældre versioner (eller generelt) kan du også bare dekomponere den sammensatte type med den rigtige syntaks:
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;
Ulempen er, at funktionen evalueres én gang for hver kolonne i funktionsoutputtet på grund af en svaghed i Postgres-forespørgselsplanlæggeren. Det er bedre at flytte opkaldet til en underforespørgsel eller CTE og dekomponere rækketypen i den ydre SELECT
. Ligesom:
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;
Men du skal navngive individuelle kolonner og kan ikke slippe afsted med SELECT *
medmindre du er ok med rækketypen i resultatet redundant.Relateret:
- Undgå flere opkald på samme funktion, når du udvider sammensat resultat
- Hvordan undgår man flere funktionsevaler med (func()).*-syntaksen i en SQL-forespørgsel?