Nếu thiết kế của bạn thực thi tính toàn vẹn tham chiếu, bạn không cần phải tham gia vào bảng residences
cho mục đích này ở tất cả. Cũng giả sử một UNIQUE
hoặc PK
ràng buộc về (residence_id, amenity_id)
(nếu không, bạn cần các truy vấn khác!)
Truy vấn tốt nhất phụ thuộc vào những gì bạn cần chính xác .
Sử dụng chức năng cửa sổ, bạn có thể thậm chí thực hiện điều này trong một cấp truy vấn duy nhất:
SELECT count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3
LIMIT 1;
Hàm cửa sổ này thêm tổng số vào mọi hàng mà không cần tổng hợp các hàng. Xem xét chuỗi sự kiện trong SELECT
truy vấn:
Do đó, bạn có thể sử dụng một truy vấn tương tự để trả về tất cả các ID đủ điều kiện (hoặc thậm chí toàn bộ hàng) và thêm số lượng vào mỗi hàng (dư thừa):
SELECT residence_id, count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3;
Nhưng tốt hơn hãy sử dụng truy vấn con, điều đó thường rẻ hơn nhiều :
SELECT count(*) AS ct
FROM (
SELECT 1
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3
) sub;
Bạn có thể trả về một mảng ID (trái ngược với set ở trên) đồng thời, hầu như không phải trả thêm bất kỳ chi phí nào:
SELECT array_agg(residence_id ) AS ids, count(*) AS ct
FROM (
SELECT residence_id
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3
) sub;
Có nhiều biến thể khác, bạn sẽ phải làm rõ kết quả mong đợi. Như thế này:
SELECT count(*) AS ct
FROM listed_amenities l1
JOIN listed_amenities l2 USING (residence_id)
JOIN listed_amenities l3 USING (residence_id)
WHERE l1.amenity_id = 48
AND l2.amenity_id = 49
AND l2.amenity_id = 50;
Về cơ bản, đó là một trường hợp của phép chia quan hệ. Chúng tôi đã tập hợp một kho kỹ thuật tại đây: