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

Nhiều lệnh gọi array_agg () trong một truy vấn

DISTINCT thường được áp dụng để sửa chữa các truy vấn bị lỗi từ bên trong và điều đó thường chậm và / hoặc không chính xác. Không nhân các hàng ở đầu, sau đó bạn không phải sắp xếp các hàng trùng lặp không mong muốn ở cuối.

Việc tham gia vào nhiều bảng n ("có nhiều") cùng một lúc sẽ nhân các hàng trong tập kết quả. Nó giống như một CROSS JOIN hoặc sản phẩm Descartes theo proxy :

  • Hai SQL LEFT JOINS tạo ra kết quả không chính xác

Có nhiều cách khác nhau để tránh sai lầm này.

Tổng hợp trước, tham gia sau

Về mặt kỹ thuật, truy vấn hoạt động miễn là bạn tham gia vào một bảng có nhiều hàng cùng một lúc trước khi bạn tổng hợp:

SELECT e.id, e.name, e.age, e.streets, arrag_agg(wd.day) AS days
FROM  (
   SELECT e.id, e.name, e.age, array_agg(ad.street) AS streets
   FROM   employees e 
   JOIN   address  ad ON ad.employeeid = e.id
   GROUP  BY e.id    -- id enough if it is defined PK
   ) e
JOIN   workingdays wd ON wd.employeeid = e.id
GROUP  BY e.id, e.name, e.age;

Tốt nhất bạn nên bao gồm khóa chính idGROUP BY nó, bởi vì nameage không nhất thiết phải là duy nhất. Bạn có thể hợp nhất hai nhân viên do nhầm lẫn.

Nhưng bạn có thể tổng hợp trong một truy vấn con trước bạn tham gia, điều đó tốt hơn trừ khi bạn có WHERE có chọn lọc điều kiện về employees :

SELECT e.id, e.name, e.age, ad.streets, arrag_agg(wd.day) AS days
FROM   employees e 
JOIN  (
   SELECT employeeid, array_agg(ad.street) AS streets
   FROM   address
   GROUP  BY 1
   ) ad ON ad.employeeid = e.id
JOIN   workingdays wd ON e.id = wd.employeeid
GROUP  BY e.id, e.name, e.age, ad.streets;

Hoặc tổng hợp cả hai:

SELECT name, age, ad.streets, wd.days
FROM   employees e 
JOIN  (
   SELECT employeeid, array_agg(ad.street) AS streets
   FROM   address
   GROUP  BY 1
   ) ad ON ad.employeeid = e.id
JOIN  (
   SELECT employeeid, arrag_agg(wd.day) AS days
   FROM   workingdays
   GROUP  BY 1
   ) wd ON wd.employeeid = e.id;

Cái cuối cùng thường nhanh hơn nếu bạn truy xuất tất cả hoặc hầu hết của các hàng trong bảng cơ sở.

Lưu ý rằng sử dụng JOIN chứ không phải LEFT JOIN xóa nhân viên khỏi kết quả không có địa chỉ hoặc không có ngày làm việc. Điều đó có thể được dự định hoặc không. Chuyển sang LEFT JOIN để giữ lại tất cả kết quả là nhân viên.

Truy vấn con có liên quan / tham gia LATERAL

Để có một lựa chọn nhỏ , Thay vào đó, tôi sẽ xem xét các truy vấn con tương quan:

SELECT name, age
    , (SELECT array_agg(street) FROM address WHERE employeeid = e.id) AS streets
    , (SELECT arrag_agg(day) FROM workingdays WHERE employeeid = e.id) AS days
FROM   employees e
WHERE  e.namer = 'peter';  -- very selective

Hoặc, với Postgres 9.3 trở lên, bạn có thể sử dụng LATERAL tham gia vì điều đó:

SELECT e.name, e.age, a.streets, w.days
FROM   employees e
LEFT   JOIN LATERAL (
   SELECT array_agg(street) AS streets
   FROM   address
   WHERE  employeeid = e.id
   GROUP  BY 1
   ) a ON true
LEFT   JOIN LATERAL (
   SELECT array_agg(day) AS days
   FROM   workingdays
   WHERE  employeeid = e.id
   GROUP  BY 1
   ) w ON true
WHERE  e.name = 'peter';  -- very selective
  • Sự khác biệt giữa LATERAL và một truy vấn con trong PostgreSQL là gì?

Truy vấn giữ lại tất cả kết quả là nhân viên.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Pg_escape_string chính xác làm được gì?

  2. Sự khác biệt giữa ngôn ngữ sql và ngôn ngữ plpgsql trong các hàm PostgreSQL

  3. Đo điểm chuẩn Giải pháp đám mây được quản lý PostgreSQL - Phần một:Amazon Aurora

  4. Tổng quan về các thủ tục được lưu trữ mới trong PostgreSQL 11

  5. Không thể tạo dịch vụ được yêu cầu [org.hibernate.engine.jdbc.env.spi.JdbcEnosystem]