Jika desain Anda menerapkan integritas referensial, Anda tidak perlu bergabung ke tabel residences
untuk tujuan ini sama sekali. Juga dengan asumsi UNIQUE
atau PK
batasan pada (residence_id, amenity_id)
(jika tidak, Anda memerlukan kueri yang berbeda!)
Kueri terbaik bergantung pada apa yang Anda butuhkan tepatnya .
Dengan menggunakan fungsi jendela, Anda bisa bahkan lakukan ini dalam satu tingkat kueri:
SELECT count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3
LIMIT 1;
Fungsi jendela ini menambahkan jumlah total ke setiap baris tanpa menggabungkan baris. Pertimbangkan urutan kejadian dalam SELECT
permintaan:
Oleh karena itu, Anda dapat menggunakan kueri serupa untuk mengembalikan semua ID yang memenuhi syarat (atau bahkan seluruh baris) dan menambahkan hitungan ke setiap baris (secara berlebihan):
SELECT residence_id, count(*) OVER () AS ct
FROM listed_amenities
WHERE amenity_id IN (48, 49, 50)
GROUP BY residence_id
HAVING count(*) = 3;
Tapi lebih baik gunakan subquery, yang biasanya jauh lebih murah :
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;
Anda bisa mengembalikan larik ID (sebagai lawan dari set di atas) pada saat yang sama, hampir tidak ada biaya lagi:
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;
Ada banyak varian lain, Anda harus mengklarifikasi hasil yang diharapkan. Seperti ini:
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;
Pada dasarnya ini adalah kasus pembagian relasional. Kami telah mengumpulkan gudang teknik di sini: