Generelt for at dekomponere rækker returneres fra en funktion og få individuelle kolonner:
SELECT * FROM account_servicetier_for_day(20424, '2014-08-12');
Med hensyn til forespørgslen:
Postgres 9.3 eller nyere
Renser med 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
nøgleordet er implicit her, funktioner kan altid henvise til tidligere FROM
genstande. Manualen:
LATERAL
kan også gå forud for et funktionskald FROM
element, men i dette tilfælde er det et støjord, fordi funktionsudtrykket kan henvise til tidligere FROM
varer under alle omstændigheder.
Relateret:
- Indsæt flere rækker i én tabel baseret på antallet i en anden tabel
Kort notation med komma i FROM
liste svarer (for det meste) til en CROSS JOIN LATERAL
(samme som [INNER] JOIN LATERAL ... ON TRUE
) og fjerner dermed rækker fra resultatet, hvor funktionskaldet ikke returnerer nogen række. For at beholde sådanne rækker skal du bruge LEFT JOIN LATERAL ... ON TRUE
:
...
FROM account_tab a
LEFT JOIN LATERAL account_servicetier_for_day(a.accountid, '2014-08-12') f ON TRUE
...
Brug heller ikke NOT IN (subquery)
når du kan undgå det. Det er den langsomste og mest vanskelige af flere måder at gøre det på:
- Vælg rækker, der ikke findes i en anden tabel
Jeg foreslår at NOT EXISTS
i stedet.
Postgres 9.2 eller ældre
Du kan kalde en sæt-retur-funktion i SELECT
liste (som er en Postgres-udvidelse af standard SQL). Af ydeevnemæssige årsager gøres dette bedst i en underforespørgsel. Dekomponér den (velkendte!) rækketype i den ydre forespørgsel for at undgå gentagen evaluering af funktionen:
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;
Relateret svar af Craig Ringer med en forklaring, hvorfor vi bedre kan dekomponere i den ydre forespørgsel:
- Hvordan undgår man flere funktionsevaler med (func()).*-syntaksen i en SQL-forespørgsel?
Postgres 10 fjernede mærkværdigheder i adfærden for sæt-returnerende funktioner i SELECT
:
- Hvad er den forventede adfærd for flere sæt-returnerende funktioner i SELECT-sætning?