I Postgres 9.3 eller senare löses detta bäst med en LATERAL
gå med:
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;
Undviker upprepad utvärdering av funktionen (för varje kolumn i utgången - funktionen måste anropas för varje inmatningsrad i båda riktningarna).LEFT JOIN LATERAL ... ON true
för att undvika att rader släpps från vänster sida om funktionen inte returnerar någon rad:
- Vad är skillnaden mellan LATERAL och en underfråga i PostgreSQL?
Uppföljning i din kommentar:
endast de utökade kolumner som skapas av funktionsanropet
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 eftersom du inte bryr dig om andra kolumner kan du förenkla till:
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;
Vilket är en implicit CROSS JOIN LATERAL
. Om funktionen faktiskt kan returnera "ingen rad" ibland, kan resultatet bli annorlunda:vi får inga NULL-värden för raderna, dessa rader är bara eliminerade - och LIMIT
räknar dem inte längre.
I äldre versioner (eller generellt) kan du också bara dekomponera den sammansatta typen med rätt syntax:
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;
Nackdelen är att funktionen utvärderas en gång för varje kolumn i funktionsutgången på grund av en svaghet i Postgres frågeplanerare. Det är bättre att flytta anropet till en underfråga eller CTE och dekomponera radtypen i den yttre SELECT
. Gilla:
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 måste namnge enskilda kolumner och kan inte komma undan med SELECT *
om du inte är ok med radtypen i resultatet redundant.Relaterat:
- Undvik flera anrop på samma funktion när du utökar sammansatta resultat
- Hur undviker man flera funktionsevaler med syntaxen (func()).* i en SQL-fråga?