W Postgresie 9.3 lub później najlepiej to rozwiązać za pomocą LATERAL
dołącz:
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;
Pozwala uniknąć powtórnej oceny funkcji (dla każdej kolumny w danych wyjściowych — funkcja musi być wywoływana dla każdego wiersza wejściowego i tak).LEFT JOIN LATERAL ... ON true
aby uniknąć upuszczania wierszy z lewej strony, jeśli funkcja nie zwraca żadnego wiersza:
- Jaka jest różnica między LATERAL a podzapytanie w PostgreSQL?
Kontynuacja w Twoim komentarzu:
tylko rozszerzone kolumny utworzone przez wywołanie funkcji
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;
Ale ponieważ nie interesują Cię inne kolumny, możesz uprościć:
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;
Który jest niejawnym CROSS JOIN LATERAL
. Jeśli funkcja może czasami zwracać "brak wiersza", wynik może być inny:nie otrzymujemy wartości NULL dla wierszy, wiersze te są po prostu eliminowane - i LIMIT
już ich nie liczy.
W starszych wersjach (lub ogólnie) możesz też po prostu rozłożyć typ złożony z odpowiednią składnią:
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;
Wadą jest to, że funkcja jest oceniana raz dla każdej kolumny w wynikach funkcji ze względu na słabość planera zapytań Postgres. Lepiej przenieść wywołanie do podzapytania lub CTE i zdekomponować typ wiersza w zewnętrznym SELECT
. Na przykład:
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;
Ale musisz nazwać poszczególne kolumny i nie możesz uciec z SELECT *
chyba że nie masz nic przeciwko zbędnemu typowi wiersza w wyniku.Powiązane:
- Unikaj wielu wywołań tej samej funkcji podczas rozwijania wyniku złożonego
- Jak uniknąć wielu ewaluacji funkcji za pomocą składni (func()).* w zapytaniu SQL?