Umumnya, untuk menguraikan baris dikembalikan dari suatu fungsi dan mendapatkan kolom individual:
SELECT * FROM account_servicetier_for_day(20424, '2014-08-12'); Adapun pertanyaannya:
Postgres 9.3 atau lebih baru
Pembersih dengan 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 kata kunci tersirat di sini, fungsi selalu dapat merujuk FROM sebelumnya item. Panduan:
LATERALjuga dapat mendahului panggilan fungsiFROMitem, tetapi dalam hal ini adalah kata derau, karena ekspresi fungsi dapat merujuk keFROMsebelumnya item dalam hal apa pun.
Terkait:
- Menyisipkan beberapa baris dalam satu tabel berdasarkan nomor di tabel lain
Notasi pendek dengan koma di FROM list (kebanyakan) setara dengan CROSS JOIN LATERAL (sama seperti [INNER] JOIN LATERAL ... ON TRUE ) dan dengan demikian menghapus baris dari hasil di mana panggilan fungsi tidak mengembalikan baris. Untuk mempertahankan baris tersebut, gunakan LEFT JOIN LATERAL ... ON TRUE :
...
FROM account_tab a
LEFT JOIN LATERAL account_servicetier_for_day(a.accountid, '2014-08-12') f ON TRUE
...
Juga, jangan gunakan NOT IN (subquery) ketika Anda bisa menghindarinya. Ini adalah beberapa cara paling lambat dan paling rumit untuk melakukannya:
- Pilih baris yang tidak ada di tabel lain
Saya sarankan NOT EXISTS sebagai gantinya.
Postgres 9.2 atau lebih lama
Anda dapat memanggil fungsi set-return di SELECT list (yang merupakan ekstensi Postgres dari SQL standar). Untuk alasan kinerja, ini paling baik dilakukan dalam subquery. Dekomposisi tipe baris (terkenal!) di kueri luar untuk menghindari evaluasi fungsi berulang:
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;
Jawaban terkait oleh Craig Ringer dengan penjelasan, mengapa kami lebih baik menguraikan di kueri luar:
- Bagaimana cara menghindari beberapa evaluasi fungsi dengan sintaks (func()).* dalam kueri SQL?
Postgres 10 menghilangkan keanehan dalam perilaku fungsi pengembalian set di SELECT :
- Apa perilaku yang diharapkan untuk beberapa fungsi pengembalian-set dalam klausa SELECT?