Nói chung, để phân tách các hàng được trả về từ một hàm và nhận các cột riêng lẻ:
SELECT * FROM account_servicetier_for_day(20424, '2014-08-12');
Đối với truy vấn:
Postgres 9.3 hoặc mới hơn
Dọn dẹp với 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
từ khóa ẩn ở đây, các hàm luôn có thể tham chiếu sớm hơn FROM
mặt hàng. Hướng dẫn sử dụng:
LATERAL
cũng có thể đứng trước một lệnh gọi hàmFROM
, nhưng trong trường hợp này, nó là một từ nhiễu, vì biểu thức hàm có thể tham chiếu đếnFROM
toearlier trong mọi trường hợp.
Có liên quan:
- Chèn nhiều hàng vào một bảng dựa trên số trong một bảng khác
Ký hiệu ngắn với dấu phẩy trong FROM
danh sách (hầu hết) tương đương với CROSS JOIN LATERAL
(giống như [INNER] JOIN LATERAL ... ON TRUE
) và do đó loại bỏ các hàng khỏi kết quả mà lệnh gọi hàm trả về không có hàng nào. Để giữ lại các hàng như vậy, hãy sử dụng LEFT JOIN LATERAL ... ON TRUE
:
...
FROM account_tab a
LEFT JOIN LATERAL account_servicetier_for_day(a.accountid, '2014-08-12') f ON TRUE
...
Ngoài ra, không sử dụng NOT IN (subquery)
khi bạn có thể tránh nó. Đây là cách chậm nhất và khó nhất trong một số cách để làm điều đó:
- Chọn các hàng không có trong bảng khác
Tôi đề nghị NOT EXISTS
thay vào đó.
Postgres 9.2 trở lên
Bạn có thể gọi hàm set-return trong SELECT
danh sách (là một phần mở rộng Postgres của SQL tiêu chuẩn). Vì lý do hiệu suất, điều này được thực hiện tốt nhất trong một truy vấn con. Phân tách loại hàng (nổi tiếng!) Trong truy vấn bên ngoài để tránh đánh giá lặp lại hàm:
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;
Câu trả lời liên quan của Craig Ringer kèm theo lời giải thích, tại sao chúng ta nên phân tách tốt hơn trong truy vấn bên ngoài:
- Làm cách nào để tránh nhiều lần trốn tránh hàm với cú pháp (func ()). * trong truy vấn SQL?
Postgres 10 đã loại bỏ các điểm kỳ lạ trong hành vi của các hàm set-return trong SELECT
:
- Hành vi mong đợi cho nhiều hàm trả về trong mệnh đề SELECT là gì?