किसी स्तंभ के प्रत्येक अनन्य मान के लिए केवल पहली पंक्तियों का चयन कैसे करें


96

मान लें कि मेरे पास ग्राहक पतों की एक तालिका है:

CName           |   AddressLine
-------------------------------
John Smith      | 123 Nowheresville
Jane Doe        | 456 Evergreen Terrace
John Smith      | 999 Somewhereelse
Joe Bloggs      | 1 Second Ave

तालिका में, जॉन स्मिथ जैसे एक ग्राहक के कई पते हो सकते हैं। मुझे इस तालिका के लिए चुनिंदा प्रश्न की आवश्यकता है कि केवल पहली पंक्ति को वापस पाया जाए जहाँ 'CName' में डुप्लिकेट हैं। इस तालिका के लिए यह 3 (या 1 को छोड़कर सभी पंक्तियों को वापस करना चाहिए - उन दो पतों में से कोई भी ठीक है लेकिन केवल एक ही वापस आ सकता है)। क्या कोई ऐसा कीवर्ड है जिसे मैं फ़िल्टर के आधार पर चयन कर सकता हूँ कि क्या सर्वर ने पहले ही कॉलम मान देखा है या नहीं?

जवाबों:


125

एक बहुत ही सरल उत्तर यदि आप कहते हैं कि आपको परवाह नहीं है कि कौन सा पता उपयोग किया जाता है।

SELECT
    CName, MIN(AddressLine)
FROM
    MyTable
GROUP BY
    CName

यदि आप पहली बार चाहते हैं, तो एक "सम्मिलित" कॉलम के अनुसार कहें, तो यह एक अलग क्वेरी है

SELECT
    M.CName, M.AddressLine,
FROM
    (
    SELECT
        CName, MIN(Inserted) AS First
    FROM
        MyTable
    GROUP BY
        CName
    ) foo
    JOIN
    MyTable M ON foo.CName = M.CName AND foo.First = M.Inserted

हालांकि 10 कॉलम का चयन करते समय इसका उपयोग इस तरह से करने का इरादा नहीं हो सकता है। यह भी लगता है कि यह बिट प्रकार के कॉलम को स्वीकार नहीं कर सकता है।
nuit9

1
@ nuit9: बेशक यह बिट और 10 कॉलम के साथ काम नहीं करेगा। इनमें से कोई भी तथ्य आपके प्रश्न में नहीं है। आप दूसरी तकनीक या बेन थुल की तकनीक का उपयोग करेंगे। मैंने जवाब दिया कि आपने विशेष रूप से क्या पूछा, आम तौर पर अधिक हल करने के तरीके के साथ।
gbn

पहला भाग कई कॉलमों के साथ काम करता है, जो कि बिट-टाइप कॉलमों के साथ नहीं है। मैंने एमएस SQL ​​सर्वर 2016 में इसका परीक्षण किया था।
नेटफेड

24

SQL 2k5 + में, आप कुछ ऐसा कर सकते हैं:

;with cte as (
  select CName, AddressLine,
  rank() over (partition by CName order by AddressLine) as [r]
  from MyTable
)
select CName, AddressLine
from cte
where [r] = 1

5
कृपया समझाएं कि रैंक, विभाजन और [r] क्या करते हैं
रॉबर्टो

10

आप row_number()पंक्ति की पंक्ति संख्या प्राप्त करने के लिए उपयोग कर सकते हैं । यह overकमांड का उपयोग करता है - एpartition by नंबर निर्दिष्ट करने के क्लॉज निर्दिष्ट order byकरता है और पंक्ति संख्या को ऑर्डर करने के लिए चयन करता है। यहां तक ​​कि अगर आपने order byअपनी क्वेरी के अंत में एक जोड़ा है , तो यह overनंबरिंग के दौरान कमांड में ऑर्डर को संरक्षित करेगा ।

select *
from mytable
where row_number() over(partition by Name order by AddressLine) = 1

6
Postgresql में, विंडो फ़ंक्शन को WHERE क्लॉज़ में अनुमति नहीं है
ekanna

3
यह न तो MS-SQL के लिए अनुमत है।
मिक्सक्सीफॉइड

1
ROW_NUMBER()WhereTeradata में खंड के रूप में अच्छी तरह से काम नहीं करता है
Pirate X

6

आप row_numer() over(partition by ...)सिंटैक्स का उपयोग कर सकते हैं जैसे:

select * from
(
select *
, ROW_NUMBER() OVER(PARTITION BY CName ORDER BY AddressLine) AS row
from myTable
) as a
where row = 1

यह क्या करता है कि यह एक कॉलम बनाता है जिसे कहा जाता है row, जो एक काउंटर है जो हर बार समान होने पर वेतन वृद्धि CNameकरता है और उन लोगों द्वारा अनुक्रमित करता है AddressLine। भव्य रूप से where row = 1, एक को चुन सकते CNameजिसका AddressLineपहले वर्णानुक्रम आता है। अगर order byथा desc, तो यह चुनेंगे CNameजिसका AddressLineपिछले वर्णानुक्रम आता है।


1

यह आपको प्रत्येक डुप्लिकेट पंक्ति की एक पंक्ति देगा। यह आपको बिट-टाइप कॉलम भी देगा, और यह कम से कम MS Sql सर्वर में काम करता है।

(select cname, address 
from (
  select cname,address, rn=row_number() over (partition by cname order by cname) 
  from customeraddresses  
) x 
where rn = 1) order by cname

यदि आप इसके बजाय सभी डुप्लिकेट ढूंढना चाहते हैं, तो बस rn = 1 को rn> 1 में बदलें। आशा है कि यह मदद करता है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.