In Postgres 9.3 of later kan dit het beste worden opgelost met een LATERAL
doe mee:
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;
Voorkomt herhaalde evaluatie van de functie (voor elke kolom in de uitvoer - de functie moet hoe dan ook voor elke invoerrij worden aangeroepen).LEFT JOIN LATERAL ... ON true
om te voorkomen dat rijen aan de linkerkant worden weggelaten als de functie geen rij retourneert:
- Wat is het verschil tussen LATERAL en een subquery in PostgreSQL?
Vervolg in je opmerking:
alleen de uitgebreide kolommen geproduceerd door de functieaanroep
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;
Maar aangezien u niet om andere kolommen geeft, kunt u het vereenvoudigen tot:
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;
Dat is een impliciete CROSS JOIN LATERAL
. Als de functie af en toe "geen rij" kan retourneren, kan het resultaat anders zijn:we krijgen geen NULL-waarden voor de rijen, die rijen worden gewoon geëlimineerd - en LIMIT
telt ze niet meer.
In oudere versies (of in het algemeen) je kunt het samengestelde type ook gewoon ontleden met de juiste syntaxis:
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;
Het nadeel is dat de functie één keer wordt geëvalueerd voor elke kolom in de functie-uitvoer vanwege een zwakte in de Postgres-queryplanner. Het is beter om de aanroep naar een subquery of CTE te verplaatsen en het rijtype te ontleden in de buitenste SELECT
. Vind ik leuk:
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;
Maar je moet individuele kolommen een naam geven en je kunt niet wegkomen met SELECT *
tenzij je in orde bent met het rijtype in het resultaat, redundant. Gerelateerd:
- Vermijd meerdere aanroepen van dezelfde functie bij het uitbreiden van het samengestelde resultaat
- Hoe vermijd je het evalueren van meerdere functies met de (func()).* syntaxis in een SQL-query?