V Postgres 9.3 nebo později to lze nejlépe vyřešit pomocí LATERAL
připojit se:
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;
Zabraňuje opakovanému vyhodnocování funkce (pro každý sloupec na výstupu – funkce musí být volána pro každý vstupní řádek v obou směrech).LEFT JOIN LATERAL ... ON true
abyste předešli vypuštění řádků z levé strany, pokud funkce nevrátí žádný řádek:
- Jaký je rozdíl mezi LATERAL a dílčím dotazem v PostgreSQL?
Následná reakce ve vašem komentáři:
pouze rozbalené sloupce vytvořené voláním funkce
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 protože vás nezajímají další sloupce, můžete to zjednodušit na:
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;
Což je implicitní CROSS JOIN LATERAL
. Pokud může funkce skutečně příležitostně vrátit „žádný řádek“, výsledek může být jiný:pro řádky nezískáme hodnoty NULL, tyto řádky jsou pouze odstraněny – a LIMIT
už je nepočítá.
Ve starších verzích (nebo obecně) můžete také jednoduše rozložit složený typ se správnou 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;
Nevýhodou je, že funkce je vyhodnocena jednou pro každý sloupec ve výstupu funkce kvůli slabosti plánovače dotazů Postgres. Je lepší přesunout volání do poddotazu nebo CTE a rozložit typ řádku ve vnějším SELECT
. Jako:
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 musíte pojmenovat jednotlivé sloupce a nemůžete se zbavit SELECT *
pokud nejste v pořádku s typem řádku ve výsledku redundantně. Související:
- Při rozbalování složeného výsledku se vyhněte vícenásobnému volání stejné funkce
- Jak se vyhnout vícenásobným hodnotám funkcí pomocí syntaxe (func()).* v dotazu SQL?