In genere, per scomporre le righe restituito da una funzione e ottenere singole colonne:
SELECT * FROM account_servicetier_for_day(20424, '2014-08-12');
Per quanto riguarda la domanda:
Postgres 9.3 o versioni successive
Pulitore con 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;
Il LATERAL
la parola chiave è implicita qui, le funzioni possono sempre fare riferimento a FROM
precedente Oggetti. Il manuale:
LATERAL
può anche precedere una chiamata di funzione FROM
item, ma in questo caso è una noise word, perché l'espressione della funzione può fare riferimento a FROM
precedenti in ogni caso.
Correlati:
- Inserisci più righe in una tabella in base al numero in un'altra tabella
Notazione breve con una virgola nel FROM
list è (per lo più) equivalente a un CROSS JOIN LATERAL
(come [INNER] JOIN LATERAL ... ON TRUE
) e quindi rimuove le righe dal risultato in cui la chiamata di funzione non restituisce alcuna riga. Per conservare tali righe, utilizza LEFT JOIN LATERAL ... ON TRUE
:
...
FROM account_tab a
LEFT JOIN LATERAL account_servicetier_for_day(a.accountid, '2014-08-12') f ON TRUE
...
Inoltre, non utilizzare NOT IN (subquery)
quando puoi evitarlo È il modo più lento e complicato per farlo:
- Seleziona le righe che non sono presenti in un'altra tabella
Suggerisco NOT EXISTS
invece.
Postgres 9.2 o precedente
Puoi chiamare una funzione di restituzione di set in SELECT
list (che è un'estensione Postgres di SQL standard). Per motivi di prestazioni, è meglio farlo in una sottoquery. Scomponi il tipo di riga (noto!) nella query esterna per evitare la valutazione ripetuta della funzione:
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;
Risposta correlata di Craig Ringer con una spiegazione, perché è meglio scomporre nella query esterna:
- Come evitare più valutazioni di funzioni con la sintassi (func()).* in una query SQL?
Postgres 10 rimosse le stranezze nel comportamento delle funzioni di ritorno degli insiemi nel SELECT
:
- Qual è il comportamento previsto per più funzioni di restituzione di set nella clausola SELECT?