PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Bản ghi trả về từ hàm có các cột được nối với nhau

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àm FROM , 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 đến FROM 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ì?


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm cách nào để thay đổi quyền sở hữu tất cả các đối tượng trong một lược đồ cụ thể trong PostgreSQL?

  2. Giải thích chi tiết hơn về đề xuất hiệu suất điều kiện JOIN so với LEFT JOIN và WHERE

  3. Cách chuyển đổi Dấu thời gian Unix thành Giá trị Ngày / Giờ trong PostgreSQL

  4. sqlalchemy.exc.NoSuchModuleError:Không thể tải plugin:sqlalchemy.dialects:postgres

  5. Làm cách nào để chọn id với nhóm ngày tối đa theo danh mục trong PostgreSQL?