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:
LATERAL
juga dapat mendahului panggilan fungsiFROM
item, tetapi dalam hal ini adalah kata derau, karena ekspresi fungsi dapat merujuk keFROM
sebelumnya 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?