मैं इस पर टिप्पणी नहीं करूंगा कि ऐसा करने के लिए एक बेहतर उपयुक्त स्कीमा है (यह काफी संभव है), लेकिन एक स्कीमा के लिए कॉलम name
और item
, निम्न क्वेरी काम करना चाहिए। (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;
विचार यह है कि हमारे पास k
. में सभी सेट कुंजियां हैं , जिसे हम तब सेट आइटम डेटा के साथ sets
. में जोड़ते हैं सेट में प्रत्येक सेट आइटम के लिए एक बार हम खोज रहे हैं, इस मामले में तीन। तीन आंतरिक में से प्रत्येक तालिका उपनामों के साथ जुड़ता है i1
, i2
और i3
उन सभी सेट नामों को फ़िल्टर करें जिनमें शामिल होने के साथ खोजा गया आइटम शामिल नहीं है। अंत में, हमारे पास sets
. के साथ एक लेफ्ट जॉइन है तालिका उपनाम के साथ ix
, जो सेट में सभी अतिरिक्त आइटम लाता है, यानी हर वह आइटम जिसे हम खोज नहीं रहे थे। ix.name
NULL
है इस मामले में कि कोई अतिरिक्त आइटम नहीं मिलता है, जो वास्तव में हम चाहते हैं, इस प्रकार WHERE
खंड। यदि सेट पाया जाता है तो क्वेरी सेट कुंजी वाली एक पंक्ति लौटाती है, अन्यथा कोई पंक्तियाँ नहीं।
संपादित करें: Collapsars उत्तर के पीछे का विचार मेरी तुलना में बहुत बेहतर प्रतीत होता है, इसलिए यहाँ इसका थोड़ा छोटा संस्करण स्पष्टीकरण के साथ दिया गया है।
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;
यहाँ विचार यह है कि सबक्वेरी s1
उन सभी सेटों की कुंजियों का चयन करता है जिनमें अन्य आइटम होते हैं जिन्हें हम ढूंढ रहे हैं। इस प्रकार, जब हमने छोड़ा sets
. में शामिल हों s1
. के साथ , s1.name
NULL
है जब सेट में केवल वे आइटम होते हैं जिन्हें हम खोज रहे हैं। फिर हम सेट कुंजी के आधार पर समूह बनाते हैं और आइटमों की गलत संख्या वाले किसी भी सेट को फ़िल्टर करते हैं। फिर हमारे पास केवल ऐसे सेट रह जाते हैं जिनमें केवल वे आइटम होते हैं जिन्हें हम खोज रहे होते हैं और सही लंबाई के होते हैं। चूंकि सेट में केवल एक बार आइटम हो सकता है, उस मानदंड को पूरा करने वाला केवल एक सेट हो सकता है, और वह वह है जिसे हम ढूंढ रहे हैं।
संपादित करें: यह मुझे अभी पता चला है कि बिना बहिष्करण के इसे कैसे किया जाए।
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;
पहला सबक्वेरी प्रत्येक सेट में आइटम्स की कुल संख्या का पता लगाता है और दूसरा प्रत्येक सेट में मेल खाने वाले आइटम्स की संख्या का पता लगाता है। जब matches.count
3 है, सेट में वे सभी आइटम हैं जिनकी हम तलाश कर रहे हैं, और यदि totals.count
3 भी है, सेट में कोई अतिरिक्त आइटम नहीं है।