Obecně rozložení řádků vrácené z funkce a získat jednotlivé sloupce:
SELECT * FROM account_servicetier_for_day(20424, '2014-08-12');
Pokud jde o dotaz:
Postgres 9.3 nebo novější
Čistič s JOIN LATERAL
:
SELECT '2014-08-12' AS day, 0 AS inbytes, 0 AS outbytes
, a.username, a.accountid, a.userid
, f.* -- but avoid duplicate column names!
FROM account_tab a
, account_servicetier_for_day(a.accountid, '2014-08-12') f -- <-- HERE
WHERE a.isdsl = 1
AND a.dslservicetypeid IS NOT NULL
AND NOT EXISTS (
SELECT 1
FROM dailyaccounting_tab
WHERE day = '2014-08-12'
AND accountid = a.accountid
)
ORDER BY a.username;
LATERAL
klíčové slovo je zde implicitní, funkce mohou vždy odkazovat dříve FROM
položky. Manuál:
LATERAL
může také předcházet volání funkceFROM
item, ale v tomto případě se jedná o šumové slovo, protože výraz funkce může odkazovat na dřívějšíFROM
položky v každém případě.
Související:
- Vložit více řádků do jedné tabulky na základě čísla v jiné tabulce
Krátký zápis s čárkou v FROM
seznam je (většinou) ekvivalentní CROSS JOIN LATERAL
(stejné jako [INNER] JOIN LATERAL ... ON TRUE
) a tím odstraní řádky z výsledku, kde volání funkce nevrací žádný řádek. Chcete-li takové řádky zachovat, použijte LEFT JOIN LATERAL ... ON TRUE
:
...
FROM account_tab a
LEFT JOIN LATERAL account_servicetier_for_day(a.accountid, '2014-08-12') f ON TRUE
...
Také nepoužívejte NOT IN (subquery)
když se tomu můžete vyhnout. Je to nejpomalejší a nejsložitější z několika způsobů, jak toho dosáhnout:
- Vyberte řádky, které se nenacházejí v jiné tabulce
Navrhuji NOT EXISTS
místo toho.
Postgres 9.2 nebo starší
V SELECT
můžete zavolat funkci vrácení sady seznam (což je Postgres rozšíření standardního SQL). Z důvodů výkonu se to nejlépe provádí v poddotazu. Rozložte (dobře známý!) typ řádku ve vnějším dotazu, abyste se vyhnuli opakovanému hodnocení funkce:
SELECT '2014-08-12' AS day, 0 AS inbytes, 0 AS outbytes
, a.username, a.accountid, a.userid
, (a.rec).* -- but avoid duplicate column names!
FROM (
SELECT *, account_servicetier_for_day(a.accountid, '2014-08-12') AS rec
FROM account_tab a
WHERE a.isdsl = 1
AND a.dslservicetypeid Is Not Null
AND NOT EXISTS (
SELECT 1
FROM dailyaccounting_tab
WHERE day = '2014-08-12'
AND accountid = a.accountid
)
) a
ORDER BY a.username;
Související odpověď Craiga Ringera s vysvětlením, proč je lepší rozložit ve vnějším dotazu:
- Jak se vyhnout vícenásobným hodnotám funkcí pomocí syntaxe (func()).* v dotazu SQL?
Postgres 10 odstranil zvláštnosti v chování funkcí vracejících sadu v SELECT
:
- Jaké je očekávané chování pro více funkcí vracejících sadu v klauzuli SELECT?