यह सबसे बड़ी-एन-प्रति-समूह समस्या है, और यह एक बहुत ही सामान्य SQL प्रश्न है।
यहां बताया गया है कि मैं इसे बाहरी जॉइन के साथ कैसे हल करता हूं:
SELECT i1.*
FROM item i1
LEFT OUTER JOIN item i2
ON (i1.category_id = i2.category_id AND i1.item_id < i2.item_id)
GROUP BY i1.item_id
HAVING COUNT(*) < 4
ORDER BY category_id, date_listed;
मैं item
. की प्राथमिक कुंजी मान रहा हूं तालिका item_id
है , और यह कि यह एक नीरस रूप से बढ़ती हुई छद्मकी है। यानी item_id
. में ज़्यादा मान item
. में एक नई पंक्ति से मेल खाती है ।
यहां बताया गया है कि यह कैसे काम करता है:प्रत्येक आइटम के लिए, कुछ अन्य आइटम हैं जो नए हैं। उदाहरण के लिए, चौथे नवीनतम आइटम की तुलना में तीन आइटम नए हैं। सबसे नए आइटम की तुलना में शून्य आइटम नए हैं। इसलिए हम प्रत्येक आइटम की तुलना करना चाहते हैं (i1
) आइटम के सेट पर (i2
) जो नए हैं और जिनकी श्रेणी i1
. के समान है . अगर उन नए आइटम की संख्या चार से कम है, i1
उनमें से एक है जिसे हम शामिल करते हैं। अन्यथा, इसे शामिल न करें।
इस समाधान की खूबी यह है कि यह काम करता है चाहे आपके पास कितनी भी श्रेणियां हों, और यदि आप श्रेणियां बदलते हैं तो काम करना जारी रखता है। कुछ श्रेणियों में आइटम की संख्या चार से कम होने पर भी यह काम करता है।
एक अन्य समाधान जो काम करता है लेकिन MySQL उपयोगकर्ता-चर सुविधा पर निर्भर करता है:
SELECT *
FROM (
SELECT i.*, @r := IF(@g = category_id, @r+1, 1) AS rownum, @g := category_id
FROM (@g:=null, @r:=0) AS _init
CROSS JOIN item i
ORDER BY i.category_id, i.date_listed
) AS t
WHERE t.rownum <= 3;
MySQL 8.0.3 ने SQL मानक विंडो फ़ंक्शंस के लिए समर्थन पेश किया। अब हम इस तरह की समस्या को अन्य RDBMS की तरह हल कर सकते हैं:
WITH numbered_item AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY item_id) AS rownum
FROM item
)
SELECT * FROM numbered_item WHERE rownum <= 4;