2010-10-22 12 views
12

मुझे "तालिका में प्रत्येक समूह के लिए शीर्ष एन पंक्तियों का चयन करना" के संबंध में एक बहुत ही आम समस्या का सामना करना पड़ रहा है।तालिका में प्रत्येक समूह के लिए शीर्ष एन पंक्तियों का चयन

id, name, hair_colour, score कॉलम के साथ एक तालिका पर विचार करें।

मुझे एक परिणाम चाहिए कि प्रत्येक बाल रंग के लिए, मुझे शीर्ष 3 स्कोरर नाम प्राप्त करें।

इस मैं वास्तव में मिला क्या मैं Rick Osborne's blogpost "sql-getting-top-n-rows-for-a-grouped-query"

पर जरूरत समाधान की उम्मीद के रूप में जब मेरे स्कोर बराबर हैं काम नहीं करता है कि हल करने के लिए।

उपरोक्त उदाहरण में परिणाम का पालन करें।

id name hair score ranknum 
--------------------------------- 
12 Kit Blonde 10 1 
    9 Becca Blonde 9 2 
    8 Katie Blonde 8 3 
    3 Sarah Brunette 10 1  
    4 Deborah Brunette 9 2 - ------- - - > if 
    1 Kim Brunette 8 3 

पंक्ति 4 Deborah Brunette 9 2 पर विचार करें। यदि यह सारा के समान ही स्कोर (10) है, तो "श्यामला" प्रकार के बालों के लिए रैंकनम 2,2,3 होगा।

इसका समाधान क्या है?

+1

आप आरडीबीएमएस का उपयोग कर रहे हैं? –

+0

यदि आप नए SQL सर्वर का उपयोग नहीं कर रहे हैं तो http://stackoverflow.com/questions/3823939/ पर इसके लिए एक समाधान है। –

उत्तर

16

आप SQL सर्वर 2005 या नए प्रयोग कर रहे हैं, तो आप इस लक्ष्य को हासिल करने के लिए रैंकिंग कार्य करता है और एक CTE उपयोग कर सकते हैं:

;WITH HairColors AS 
(SELECT id, name, hair, score, 
     ROW_NUMBER() OVER(PARTITION BY hair ORDER BY score DESC) as 'RowNum' 
) 
SELECT id, name, hair, score 
FROM HairColors 
WHERE RowNum <= 3 

यह CTE होगा "विभाजन" hair स्तंभ के मूल्य के आधार पर आपके डेटा , और प्रत्येक विभाजन तब स्कोर (अवरोही) द्वारा क्रमबद्ध होता है और एक पंक्ति संख्या प्राप्त करता है; प्रत्येक विभाजन के लिए उच्चतम स्कोर 1 है, फिर 2 आदि

तो यदि आप प्रत्येक समूह के शीर्ष 3 को देखना चाहते हैं, तो केवल उन पंक्तियों का चयन करें जिनके पास सीटीई से RowNum 3 या उससे कम (1, 2, 3) है) -> तुम वहाँ जाओ!

+0

ROW_NUMBER() ओवर (स्कोर डीईएससी द्वारा बालों के आदेश द्वारा पार्टिशन) 'रोवनम' के रूप में) इस लाइन में ब्रैकेट संतुलित नहीं है। क्या यह डीबी 2 एसक्यूएल व्याकरण के साथ संगत है? – zinking

+0

@ ज़िंकिंग: धन्यवाद - एक बंद माता पिता बहुत सारे थे .. इसे ठीक कर दिया! अगर डीबी 2 इसका समर्थन करता है तो मुझे पता नहीं है (डीबी 2 पर्याप्त नहीं जानते) - लेकिन यह निश्चित रूप से एक एएनएसआई/आईएसओ एसक्यूएल मानक निर्माण है - माइक्रोसॉफ्ट की आविष्कारित सुविधा नहीं :-) –

+1

शित, यह सिर्फ मेरा दिन बना! सीटीई के लिए क्या परिचय है! –

0

जिस तरह से एल्गोरिदम रैंक के साथ आता है, रैंक उत्पन्न करने के लिए, प्रश्न में लड़की के बराबर या उससे अधिक अंक के साथ क्रॉस-उत्पाद में पंक्तियों की संख्या को गिनना है। इसलिए समस्या मामले के बारे में आप बात कर रहे हैं में, सारा के ग्रिड की तरह

a.name | a.score | b.name | b.score 
-------+---------+---------+-------- 
Sarah | 9  | Sarah | 9 
Sarah | 9  | Deborah | 9 

और इसी तरह डेबोरा, जिसके कारण दोनों लड़कियों यहाँ 2 के एक रैंक पाने के लिए विचार करेंगे।

समस्या यह है कि जब बराबर हैं, सभी लड़कियों न्यूनतम मूल्य बंधे रेंज में इस गणना, जब आप उन्हें सबसे अधिक मूल्य के बजाय लेने के लिए चाहते हैं की वजह से लेते हैं। मुझे लगता है कि एक साधारण परिवर्तन इसे ठीक कर सकता है:

अधिक से अधिक या बराबर तुलना के बजाय, सख्ती से बेहतर लड़कियों की संख्या की गणना करने के लिए तुलना में सख्त से अधिक का उपयोग करें। फिर, उसमें एक जोड़ें और आपके पास रैंक है (जो उचित संबंधों के साथ सौदा करेगा)। तो आंतरिक चयन होगा:

SELECT a.id, COUNT(*) + 1 AS ranknum 
FROM girl AS a 
    INNER JOIN girl AS b ON (a.hair = b.hair) AND (a.score < b.score) 
GROUP BY a.id 
HAVING COUNT(*) <= 3 

क्या कोई इस दृष्टिकोण के साथ कोई समस्या देख सकता है जो मेरी सूचना से बच निकला है?

+0

क्या यह वर्गिक समय में नहीं चलता है? – b0fh

0

उपयोग इस यौगिक का चयन जो ओ पी समस्या संभालती है ठीक से

SELECT g.* FROM girls as g 
WHERE g.score > IFNULL((SELECT g2.score FROM girls as g2 
       WHERE g.hair=g2.hair ORDER BY g2.score DESC LIMIT 3,1), 0) 

ध्यान दें कि आप जब तालिका लड़कियोंबाल के कुछ प्रकार के लिए कम पंक्तियां हैं IFNULL यहाँ मामले को संभालने के लिए उपयोग करने की आवश्यकता तो हम करना चाहते हैं एसक्यूएल उत्तर में देखें (ओपी मामले में यह 3 आइटम है)।

संबंधित मुद्दे