Ogólnie aby rozłożyć wiersze zwrócone z funkcji i uzyskać poszczególne kolumny:
SELECT * FROM account_servicetier_for_day(20424, '2014-08-12');
Co do zapytania:
Postgres 9.3 lub nowszy
Czyszczenie z 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
słowo kluczowe jest tutaj niejawne, funkcje zawsze mogą odwoływać się do wcześniejszego FROM
rzeczy. Instrukcja:
LATERAL
może również poprzedzać wywołanie funkcji FROM
item, ale w tym przypadku jest to słowo zakłócające, ponieważ wyrażenie funkcji może odnosić się do wcześniejszego FROM
przedmioty w każdym przypadku.
Powiązane:
- Wstaw wiele wierszy w jednej tabeli na podstawie numeru w innej tabeli
Krótka notacja z przecinkiem w FROM
lista jest (w większości) odpowiednikiem CROSS JOIN LATERAL
(tak samo jak [INNER] JOIN LATERAL ... ON TRUE
), a tym samym usuwa wiersze z wyniku, w których wywołanie funkcji nie zwraca żadnego wiersza. Aby zachować takie wiersze, użyj LEFT JOIN LATERAL ... ON TRUE
:
...
FROM account_tab a
LEFT JOIN LATERAL account_servicetier_for_day(a.accountid, '2014-08-12') f ON TRUE
...
Nie używaj także NOT IN (subquery)
kiedy możesz tego uniknąć. Jest to najwolniejszy i najtrudniejszy z kilku sposobów, aby to zrobić:
- Wybierz wiersze, których nie ma w innej tabeli
Proponuję NOT EXISTS
zamiast tego.
Postgres 9.2 lub starszy
Możesz wywołać funkcję zwracającą zestaw w SELECT
list (która jest rozszerzeniem Postgresa standardowego SQL). Ze względu na wydajność najlepiej jest to zrobić w podzapytaniu. Zdekomponuj (dobrze znany!) typ wiersza w zewnętrznym zapytaniu, aby uniknąć powtórnej oceny funkcji:
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;
Powiązana odpowiedź Craiga Ringera z wyjaśnieniem, dlaczego lepiej rozkładać się w zewnętrznym zapytaniu:
- Jak uniknąć wielu ewaluacji funkcji za pomocą składni (func()).* w zapytaniu SQL?
Postgres 10 usunięto osobliwości w zachowaniu funkcji zwracających zestaw w SELECT
:
- Jakie jest oczekiwane zachowanie wielu funkcji zwracających zestaw w klauzuli SELECT?