2009-07-31 11 views
12

तो मैं जानता हूँ कि यह एक बहुत गूंगा सवाल है, लेकिन (के रूप में नहीं बल्कि lengthily शीर्षक कहते हैं) मुझे पता है कि निम्न कैसे करना चाहते हैं:आप एक कॉलम द्वारा कैसे समूहबद्ध करते हैं और टी/एसक्यूएल में किसी अन्य कॉलम के न्यूनतम मान के साथ एक पंक्ति पुनर्प्राप्त करते हैं?

मैं इस तरह एक मेज है:

ID Foo Bar Blagh 
---------------- 
1 10 20 30 
2 10 5 1 
3 20 50 40 
4 20 75 12 

मैं फू द्वारा समूह चाहते हैं, तो कम से कम बार साथ पंक्तियों को बाहर खींच निम्नलिखित यानी मैं चाहता हूँ,:

ID Foo Bar Blagh 
---------------- 
2 10 5 1 
3 20 50 40 

मैं के लिए मुझे के जीवन सही एसक्यूएल बाहर काम नहीं कर सकता यह पुनः प्राप्त करने के। मैं कुछ ऐसा करना चाहते हैं:

SELECT ID, Foo, Bar, Blagh 
FROM Table 
GROUP BY Foo 
HAVING(MIN(Bar)) 

हालांकि यह स्पष्ट रूप से काम नहीं करता है के रूप में है कि वाक्य रचना और आईडी होने पूरी तरह से अवैध है, फू, बार और Blagh इकट्ठा नहीं किया जाता।

मैं क्या गलत कर रहा हूं?

उत्तर

11

This लगभग वही प्रश्न है, लेकिन इसमें कुछ जवाब हैं!

यहाँ मुझे अपनी मेज तक मजाक है:

declare @Borg table (
    ID int, 
    Foo int, 
    Bar int, 
    Blagh int 
) 
insert into @Borg values (1,10,20,30) 
insert into @Borg values (2,10,5,1) 
insert into @Borg values (3,20,50,70) 
insert into @Borg values (4,20,75,12) 

तो फिर तुम एक गुमनाम आंतरिक डेटा आप चाहते हैं पाने के लिए शामिल हो कर सकते हैं।

select B.* from @Borg B inner join 
(
    select Foo, 
     MIN(Bar) MinBar 
    from @Borg 
    group by Foo 
) FO 
on FO.Foo = B.Foo and FO.MinBar = B.Bar 

संपादित एडम रॉबिन्सन काम आते हुए बताया गया है "इस समाधान जब बार की न्यूनतम मूल्य दोहराया गया है एकाधिक पंक्तियों वापस जाने के लिए की क्षमता है, और foo के किसी भी मूल्य समाप्त जहां बार null कि"

कि

आपके उपयोगकेस के आधार पर, डुप्लिकेट मान जहां बार डुप्लिकेट किया गया हो, वैध हो सकता है - यदि आप बोर्ग में सभी मानों को ढूंढना चाहते थे, जहां बार न्यूनतम था, तो दोनों परिणाम होने का तरीका लगता है।

आप तो आप एक स्वीकार्य उच्च (या कम) मूल्य के साथ शून्य coalesce सकता है (यह एक हैक है), क्षेत्र जिन पर आप (इस मामले में मिन द्वारा) एकत्रित कर रहे हैं में NULLs पर कब्जा करने की जरूरत है:

... 
MIN(coalesce(Bar,1000000)) MinBar -- A suitably high value if you want to exclude this row, make it suitably low to include 
... 

या आप यूनियन के लिए जा सकते हैं और ऐसे सभी मूल्यों को अपने परिणाम के नीचे संलग्न कर सकते हैं।

on FO.Foo = B.Foo and FO.MinBar = B.Bar 
union select * from @Borg where Bar is NULL 

बाद होगा एक ही Foo मूल्य के साथ @Borg में नहीं समूह मूल्यों क्योंकि यह उन दोनों के बीच चयन करने के लिए कैसे पता नहीं है।

+1

+1 कुछ एसक्यूएल को एक साथ खींचने के बजाय जोड़ने के लिए +1 ... – gbn

+2

Cheeky। जब मैं टिप्पणी करता हूं संपादन। – gbn

+1

@ जीबीएन मैं अपने जवाब में "मूल्य जोड़ रहा था"! :) – butterchicken

1

मेरी समझ यह है कि आप वास्तव में इसे एक ही बार में नहीं कर सकते हैं।

select Foo, min(Bar) from table group by Foo 

, आपको प्रत्येक विशिष्ट फू के लिए न्यूनतम बार मिल जाता है। लेकिन आप उस न्यूनतम आईडी को उस विशेष आईडी से जोड़ नहीं सकते हैं, क्योंकि उस बार मान के साथ एक से अधिक पंक्ति हो सकती है।

select * from Table t 
join (
    select Foo, min(Bar) as minbar 
    from Table group by Foo 
) tt on t.Foo=tt.Foo and t.Bar=tt.minbar 

ध्यान दें कि अगर वहाँ न्यूनतम बार मूल्य के साथ पंक्ति एक से अधिक, आप उन सभी से ऊपर क्वेरी के साथ मिल जाएगा:

आप क्या कर सकते हैं कुछ इस तरह है।

अब, मैं एक एसक्यूएल गुरु होने का दावा कर रहा हूँ नहीं है, और यह देर हो चुकी है मैं कहाँ हूँ, और मैं कुछ कमी हो सकती है, लेकिन वहाँ है मेरी $ 0.02 :)

1

यह मदद कर सकता है:

DECLARE @Table TABLE(
     ID INT, 
     Foo FLOAT, 
     Bar FLOAT, 
     Blah FLOAT 
) 

INSERT INTO @Table (ID,Foo,Bar,Blah) SELECT 1, 10 ,20 ,30 
INSERT INTO @Table (ID,Foo,Bar,Blah) SELECT 2, 10 ,5 ,1 
INSERT INTO @Table (ID,Foo,Bar,Blah) SELECT 3, 20 ,50 ,40 
INSERT INTO @Table (ID,Foo,Bar,Blah) SELECT 4, 20 ,75 ,12 

SELECT t.* 
FROM @Table t INNER JOIN 
     (
      SELECT Foo, 
        MIN(Bar) MINBar 
      FROM @Table 
      GROUP BY Foo 
     ) Mins ON t.Foo = Mins.Foo 
       AND t.Bar = Mins.MINBar 
3
select 
    ID, 
    Foo, 
    Bar, 
    Blagh 
from Table 
join (
    select 
    ID, 
    (row_number() over (order by foo, bar) - rank() over (order by foo)) as rowNumber 
) t on t.ID = Table.ID and t.rowNumber = 0 

यह फिर मेज पर मिलती है, लेकिन इस बार के रूप में अगर यह foo के प्रत्येक मान के भीतर आरोही जाते, तब bar के लिए मूल्य के लिए एक रिश्तेदार पंक्ति संख्या कहते हैं। rowNumber = 0 पर फ़िल्टर करके, यह foo के प्रत्येक मान के लिए bar के लिए केवल निम्नतम मानों का चयन करता है। यह group by खंड को प्रभावी रूप से हटा देता है, क्योंकि अब आप केवल foo प्रति एक पंक्ति पुनर्प्राप्त कर रहे हैं।

+0

इसका उल्लेख करने के लायक MSSQL2005 से पहले काम नहीं करता है जब row_number() पेश किया गया था। – butterchicken

1

एक अन्य विकल्प निम्नलिखित की तर्ज पर कुछ होगा:

DECLARE @TEST TABLE( ID int, Foo int, Bar int, Blagh int) 
INSERT INTO @TEST VALUES (1,10,20,30) 
INSERT INTO @TEST VALUES (2,10,5,1) 
INSERT INTO @TEST VALUES (3,20,50,70) 
INSERT INTO @TEST VALUES (4,20,75,12) 

SELECT Id, Foo, Bar, Blagh 
FROM (
     SELECT id, Foo, Bar, Blagh, CASE WHEN (Min(Bar) OVER(PARTITION BY FOO) = Bar) THEN 1 ELSE 0 END as MyRow 
     FROM @TEST) t 
WHERE MyRow = 1 

हालांकि यह अभी भी एक उप क्वेरी यह जरूरत के लिए मिलती है को खत्म करता है की आवश्यकता है।

बस एक और विकल्प।

0
declare @Borg table (
    ID int, 
    Foo int, 
    Bar int, 
    Blagh int 
) 
insert into @Borg values (1,10,20,30) 
insert into @Borg values (2,10,5,1) 
insert into @Borg values (3,20,50,70) 
insert into @Borg values (4,20,75,12) 

select * from @Borg 

select Foo,Bar,Blagh from @Borg b 
where Bar = (select MIN(Bar) from @Borg c where c.Foo = b.Foo) 
+0

किसी अन्य व्यक्ति से उत्तर कॉपी न करें। –

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