मैं (या मैं कैसे कर सकता हूँ) कई स्तंभों पर DISTINCT का चयन करें?


415

मुझे एक तालिका से सभी पंक्तियों को पुनः प्राप्त करने की आवश्यकता है जहां 2 कॉलम संयुक्त हैं सभी अलग हैं। इसलिए मैं सभी बिक्री चाहता हूं जो किसी भी अन्य बिक्री के लिए नहीं है जो उसी दिन उसी कीमत पर हुई थी। बिक्री जो दिन और मूल्य के आधार पर अद्वितीय है, एक सक्रिय स्थिति में अपडेट हो जाएगी।

तो मैं सोच रहा हूँ:

UPDATE sales
SET status = 'ACTIVE'
WHERE id IN (SELECT DISTINCT (saleprice, saledate), id, count(id)
             FROM sales
             HAVING count = 1)

लेकिन मेरा दिमाग उससे कहीं आगे जा रहा है।

जवाबों:


436
SELECT DISTINCT a,b,c FROM t

है मोटे तौर पर के बराबर:

SELECT a,b,c FROM t GROUP BY a,b,c

यह एक अच्छा विचार है कि ग्रुप बाय सिंटैक्स का उपयोग किया जाए, क्योंकि यह अधिक शक्तिशाली है।

आपकी क्वेरी के लिए, मैं इसे इस तरह से करूंगा:

UPDATE sales
SET status='ACTIVE'
WHERE id IN
(
    SELECT id
    FROM sales S
    INNER JOIN
    (
        SELECT saleprice, saledate
        FROM sales
        GROUP BY saleprice, saledate
        HAVING COUNT(*) = 1 
    ) T
    ON S.saleprice=T.saleprice AND s.saledate=T.saledate
 )

117
यह क्वेरी, जबकि सही है और अब वर्ष के लिए स्वीकार की जा रही है, बेहद अक्षम और अनावश्यक रूप से ऐसा है। यह प्रयोग न करें। मैंने एक विकल्प दिया और दूसरे उत्तर में कुछ स्पष्टीकरण दिया।
एरविन ब्रान्डस्टेट्टर

1
DISTINCT a, b, c FROM t का चयन ठीक उसी प्रकार से नहीं किया जाता है जैसे कि a, b, c FROM t GROUP द्वारा a, b, c?
अकालगर

8
@famargar साधारण मामले के लिए, अभी तक, लेकिन उनके शब्दार्थ अलग-अलग हैं, और वे एक बड़ी क्वेरी बनाते समय चरण के लिए आप क्या कर सकते हैं, इसके संदर्भ में भिन्न हैं। इसके अलावा, तकनीकी मंचों पर लोग अक्सर चीजों के बारे में बेहद पांडित्यपूर्ण हो सकते हैं, मुझे इस संदर्भ में अक्सर अपने पोस्ट में वैसल शब्द जोड़ने के लिए उपयोगी लगता है।
जोएल कोएहॉर्न

344

यदि आप अब तक जवाब एक साथ रखते हैं, तो सफाई करें और सुधार करें, आप इस बेहतर क्वेरी पर पहुंचेंगे:

UPDATE sales
SET    status = 'ACTIVE'
WHERE  (saleprice, saledate) IN (
    SELECT saleprice, saledate
    FROM   sales
    GROUP  BY saleprice, saledate
    HAVING count(*) = 1 
    );

जो दोनों में से बहुत तेज है। कारक 10 - 15 द्वारा वर्तमान में स्वीकार किए गए उत्तर का प्रदर्शन Nukes (PostgreSQL 8.4 और 9.1 पर मेरे परीक्षणों में)।

लेकिन यह अभी भी इष्टतम से दूर है। NOT EXISTSबेहतर प्रदर्शन के लिए एक (एंटी-) सेमी-जॉइन का उपयोग करें । EXISTSमानक SQL है, हमेशा के लिए (कम से कम PostgreSQL 7.2 के बाद से, इस सवाल के पूछे जाने से बहुत पहले) के आसपास है और प्रस्तुत आवश्यकताओं को फिट बैठता है:

UPDATE sales s
SET    status = 'ACTIVE'
WHERE  NOT EXISTS (
   SELECT FROM sales s1                     -- SELECT list can be empty for EXISTS
   WHERE  s.saleprice = s1.saleprice
   AND    s.saledate  = s1.saledate
   AND    s.id <> s1.id                     -- except for row itself
   )
AND    s.status IS DISTINCT FROM 'ACTIVE';  -- avoid empty updates. see below

db <> यहाँ
field पुरानी SQL फ़ेल्ड

पंक्ति की पहचान करने के लिए अद्वितीय कुंजी

यदि आपके पास तालिका ( idउदाहरण में) के लिए एक प्राथमिक या अद्वितीय कुंजी नहीं है , तो आप ctidइस क्वेरी के उद्देश्य के लिए सिस्टम कॉलम के साथ स्थानापन्न कर सकते हैं (लेकिन कुछ अन्य उद्देश्यों के लिए नहीं):

   AND    s1.ctid <> s.ctid

प्रत्येक तालिका में एक प्राथमिक कुंजी होनी चाहिए। यदि आपके पास अभी तक एक नहीं है, तो उसे जोड़ें। मैं 10+ पोस्टग्रेज में एक serialया एक IDENTITYकॉलम सुझाता हूं ।

सम्बंधित:

यह कैसे तेज है?

EXISTSएंटी-सेमी-ज्वाइन में सबकुछ का मूल्यांकन जैसे ही पहली बार पाया जाता है (आगे देखने का कोई मतलब नहीं) बंद कर सकता है। कुछ डुप्लिकेट के साथ एक आधार तालिका के लिए यह केवल अपेक्षाकृत अधिक कुशल है। डुप्लिकेट के बहुत सारे के साथ इस हो जाता है जिस तरह से और अधिक कुशल।

खाली अपडेट को छोड़ दें

उन पंक्तियों के लिए जिनके पास पहले से ही status = 'ACTIVE'यह अपडेट है, कुछ भी नहीं बदलेगा, लेकिन फिर भी पूरी लागत पर एक नया पंक्ति संस्करण डालें (मामूली अपवाद लागू होते हैं)। आम तौर पर, आप यह नहीं चाहते हैं। इससे WHEREबचने के लिए ऊपर दी गई एक और शर्त जोड़ें और इसे और तेज़ करें:

यदि statusपरिभाषित किया गया है NOT NULL, तो आप इसे सरल कर सकते हैं:

AND status <> 'ACTIVE';

कॉलम के डेटा प्रकार को <>ऑपरेटर का समर्थन करना चाहिए । कुछ प्रकार की तरह jsonनहीं है। देख:

NULL हैंडलिंग में सूक्ष्म अंतर

यह क्वेरी ( जोएल द्वारा वर्तमान में स्वीकृत उत्तर के विपरीत ) NULL मूल्यों को समान नहीं मानती है। निम्नलिखित दो पंक्तियाँ (saleprice, saledate)"विशिष्ट" के रूप में योग्य होंगी (हालांकि मानव आंख के समान दिखती हैं):

(123, NULL)
(123, NULL)

इसके अलावा एक अद्वितीय सूचकांक में और लगभग कहीं भी गुजरता है, क्योंकि NULL मान SQL मानक के अनुसार समान की तुलना नहीं करते हैं। देख:

OTOH, GROUP BY, DISTINCTया DISTINCT ON ()समकक्ष के रूप में इलाज शून्य मान। आप जो हासिल करना चाहते हैं, उसके आधार पर एक उपयुक्त क्वेरी शैली का उपयोग करें। NULL तुलना करने के लिए आप इस तेज़ क्वेरी का उपयोग किसी भी या सभी तुलनाओं के IS NOT DISTINCT FROMबजाय कर सकते हैं =। अधिक:

यदि तुलना किए जा रहे सभी कॉलम परिभाषित किए गए हैं NOT NULL, तो असहमति के लिए कोई जगह नहीं है।


16
अच्छा उत्तर। मैं एक sql सर्वर लड़का हूं, इसलिए IN () चेक के साथ टपल का उपयोग करने का पहला सुझाव मेरे पास नहीं होगा। मौजूद नहीं है सुझाव आमतौर पर आंतरिक निष्पादन में sql सर्वर में एक ही निष्पादन योजना के साथ समाप्त होने वाला है।
जोएल कोएहॉर्न

2
अच्छा लगा। स्पष्टीकरण उत्तर के मूल्य को बहुत बढ़ाता है। मैं Oracle के साथ कुछ परीक्षण चलाने के लिए लगभग ललचा गया हूं, यह देखने के लिए कि पोस्टग्रेज और SQLServer के साथ योजनाओं की तुलना कैसे की जाती है।
पीटर

2
@alairock: आपको वह कहाँ मिला? पोस्टग्रेज के लिए, विपरीत सच है। सभी पंक्तियों की गिनती करते समय, count(*)की तुलना में अधिक कुशल है count(<expression>)। कर के देखो। एग्रीगेट फंक्शन के इस संस्करण के लिए पोस्टग्रेज का तेज़ कार्यान्वयन है। शायद आप कुछ अन्य RDBMS के साथ Postgres को भ्रमित कर रहे हैं?
इरविन ब्रान्डसेट्टर

6
@alairock: मुझे उस पृष्ठ का सह-लेखक होना है और यह किसी भी प्रकार की बात नहीं कहता है।
इरविन ब्रान्डेसटेटर

2
@ErwinBrandstetter, आप हमेशा ढेर पर अपने उत्तरों के साथ बिंदु पर होते हैं। आपने वर्षों तक लगभग अकल्पनीय तरीकों से मदद की है। इस उदाहरण के लिए, मैं अपनी समस्या को हल करने के लिए कुछ अलग तरीके जानता था, लेकिन मैं यह देखना चाहता था कि किसी ने संभावनाओं के बीच दक्षता का परीक्षण किया है। धन्यवाद।
वेबवैंडर

24

आपकी क्वेरी के साथ समस्या यह है कि ग्रुप बाय क्लॉज़ का उपयोग करते समय (जो कि आप अनिवार्य रूप से विशिष्ट का उपयोग करके करते हैं) आप केवल उन कॉलम का उपयोग कर सकते हैं जिन्हें आप समूह में या समुच्चय कार्यों द्वारा समूह में करते हैं। आप कॉलम आईडी का उपयोग नहीं कर सकते क्योंकि संभावित रूप से भिन्न मूल्य हैं। आपके मामले में HAVING क्लॉज के कारण हमेशा केवल एक ही मूल्य होता है, लेकिन अधिकांश RDBMS पहचानने के लिए पर्याप्त स्मार्ट नहीं होते हैं।

हालांकि यह काम करना चाहिए (और इसमें शामिल होने की आवश्यकता नहीं है):

UPDATE sales
SET status='ACTIVE'
WHERE id IN (
  SELECT MIN(id) FROM sales
  GROUP BY saleprice, saledate
  HAVING COUNT(id) = 1
)

आप MIN के बजाय MAX या AVG का उपयोग कर सकते हैं, केवल एक फ़ंक्शन का उपयोग करना महत्वपूर्ण है जो स्तंभ का मान लौटाता है यदि केवल एक मिलान पंक्ति है।


1

मैं एक कॉलम 'GrondOfLucht' से अलग-अलग मानों का चयन करना चाहता हूं, लेकिन उन्हें क्रम में क्रमबद्ध किया जाना चाहिए जैसा कि कॉलम 'सॉर्टरिंग' में दिया गया है। मैं केवल एक कॉलम का उपयोग करके अलग-अलग मान प्राप्त नहीं कर सकता

Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering

यह कॉलम को 'सॉर्टरिंग' भी देगा और क्योंकि 'GrondOfLucht' और 'सॉर्टरिंग' अद्वितीय नहीं है, परिणाम सभी पंक्तियाँ होंगी।

'सॉर्टरिंग' द्वारा दिए गए आदेश में 'GrondOfLucht' के रिकॉर्ड का चयन करने के लिए ग्रुप का उपयोग करें

SELECT        GrondOfLucht
FROM            dbo.CorWijzeVanAanleg
GROUP BY GrondOfLucht, sortering
ORDER BY MIN(sortering)

यह मूल रूप से समझाता है कि स्वीकृत उत्तर क्या करता है, लेकिन मैं उदाहरण के लिए ऐसे नामों का उपयोग नहीं करने की सलाह दूंगा (कम से कम उनका अनुवाद करें)। पुनश्च: मैं हमेशा सभी परियोजनाओं में अंग्रेजी में सब कुछ नाम रखने की सलाह देता हूं, भले ही आप डच हों।
केर्विन स्नीजर्स

0

यदि आपका DBMS इस तरह कई कॉलम के साथ अलग का समर्थन नहीं करता है:

select distinct(col1, col2) from table

सामान्य रूप से बहु का चयन सुरक्षित रूप से इस प्रकार किया जा सकता है:

select distinct * from (select col1, col2 from table ) as x

चूंकि यह अधिकांश DBMS पर काम कर सकता है और यह समूह द्वारा समाधान की तुलना में तेज़ होने की उम्मीद है क्योंकि आप समूह कार्यक्षमता से बच रहे हैं।

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