Tôi sẽ không bình luận về việc liệu có một lược đồ phù hợp hơn để thực hiện việc này hay không (hoàn toàn có thể xảy ra), nhưng đối với một lược đồ có các cột name
và item
, truy vấn sau sẽ hoạt động. (cú pháp mysql)
SELECT k.name
FROM (SELECT DISTINCT name FROM sets) AS k
INNER JOIN sets i1 ON (k.name = i1.name AND i1.item = 1)
INNER JOIN sets i2 ON (k.name = i2.name AND i2.item = 3)
INNER JOIN sets i3 ON (k.name = i3.name AND i3.item = 5)
LEFT JOIN sets ix ON (k.name = ix.name AND ix.item NOT IN (1, 3, 5))
WHERE ix.name IS NULL;
Ý tưởng là chúng ta có tất cả các khóa đã đặt trong k
, sau đó chúng tôi kết hợp với dữ liệu mục đã đặt trong sets
một lần cho mỗi mục đã đặt trong bộ mà chúng tôi đang tìm kiếm, ba trong trường hợp này. Mỗi một trong ba liên kết bên trong với bí danh bảng i1
, i2
và i3
lọc ra tất cả các tên đã đặt không chứa mục được tìm kiếm với phép nối đó. Cuối cùng, chúng ta có một phép nối bên trái với sets
với bí danh bảng ix
, mang lại tất cả các mục bổ sung trong bộ, tức là mọi mục mà chúng tôi không tìm kiếm. ix.name
là NULL
trong trường hợp không tìm thấy các mục bổ sung, đó là chính xác những gì chúng tôi muốn, do đó, WHERE
mệnh đề. Truy vấn trả về một hàng chứa khóa tập hợp nếu tập hợp được tìm thấy, không có hàng nào khác.
Chỉnh sửa: Ý tưởng đằng sau câu trả lời của sập có vẻ tốt hơn nhiều so với của tôi, vì vậy, đây là phiên bản ngắn hơn một chút cùng với lời giải thích.
SELECT sets.name
FROM sets
LEFT JOIN (
SELECT DISTINCT name
FROM sets
WHERE item NOT IN (1, 3, 5)
) s1
ON (sets.name = s1.name)
WHERE s1.name IS NULL
GROUP BY sets.name
HAVING COUNT(sets.item) = 3;
Ý tưởng ở đây là truy vấn con s1
chọn các khóa của tất cả các bộ có chứa các mục khác mà chúng tôi đang tìm kiếm. Do đó, khi chúng ta rời khỏi tham gia sets
với s1
, s1.name
là NULL
khi tập hợp chỉ chứa các mục mà chúng tôi đang tìm kiếm. Sau đó, chúng tôi nhóm theo khóa thiết lập và lọc ra bất kỳ nhóm nào có số lượng mục không chính xác. Sau đó, chúng tôi chỉ còn lại những bộ chỉ chứa các mục chúng tôi đang tìm kiếm và có độ dài chính xác. Vì các bộ chỉ có thể chứa một mục một lần, nên chỉ có thể có một bộ đáp ứng tiêu chí đó và đó là bộ chúng tôi đang tìm kiếm.
Chỉnh sửa: Nó chỉ cho tôi biết cách thực hiện điều này mà không cần loại trừ.
SELECT totals.name
FROM (
SELECT name, COUNT(*) count
FROM sets
GROUP BY name
) totals
INNER JOIN (
SELECT name, COUNT(*) count
FROM sets
WHERE item IN (1, 3, 5)
GROUP BY name
) matches
ON (totals.name = matches.name)
WHERE totals.count = 3 AND matches.count = 3;
Truy vấn con đầu tiên tìm tổng số các mục trong mỗi tập hợp và truy vấn thứ hai tìm ra tổng số các mục phù hợp trong mỗi tập hợp. Khi matches.count
là 3, tập hợp có tất cả các mục mà chúng tôi đang tìm kiếm và nếu totals.count
cũng là 3, bộ không có thêm bất kỳ mục nào.