कई स्तंभों पर DISTINCT की गिनती


212

क्या इस तरह एक क्वेरी करने का एक बेहतर तरीका है:

SELECT COUNT(*) 
FROM (SELECT DISTINCT DocumentId, DocumentSessionId
      FROM DocumentOutputItems) AS internalQuery

मुझे इस तालिका से अलग-अलग आइटमों की संख्या गिनने की आवश्यकता है, लेकिन अलग दो कॉलमों से अधिक है।

मेरी क्वेरी ठीक काम करती है लेकिन मैं सोच रहा था कि क्या मैं केवल एक क्वेरी (उप-क्वेरी का उपयोग किए बिना) अंतिम परिणाम प्राप्त कर सकता हूं


IordanTanev, मार्क ब्रैकेट, आरसी - उत्तर के लिए धन्यवाद, यह एक अच्छी कोशिश थी, लेकिन आपको यह जांचने की आवश्यकता है कि आप एसओ को पोस्ट करने से पहले क्या कर रहे हैं। आपके द्वारा प्रदान की जाने वाली क्वेरी मेरी क्वेरी के बराबर नहीं हैं। आप आसानी से देख सकते हैं कि मेरे पास हमेशा एक स्केलर होता है, लेकिन आपकी क्वेरी कई पंक्तियों को वापस कर देती है।
नोवित्ज़स्की

उत्तर में से एक से अपनी स्पष्ट टिप्पणी को शामिल करने के लिए बस सवाल को अपडेट किया
जेफ

जानकारी के लिए: community.oracle.com/ideas/18664
Quetzalcoatl

यह अच्छा प्रश्न है। मैं यह भी सोच रहा था कि क्या ऐसा करने का एक सरल तरीका था
अनुपम

जवाबों:


73

यदि आप प्रदर्शन में सुधार करने की कोशिश कर रहे हैं, तो आप दो स्तंभों के हैश या संक्षिप्त मूल्य पर एक निरंतर कम्प्यूटेड कॉलम बनाने का प्रयास कर सकते हैं।

एक बार यह बने रहने के बाद, बशर्ते स्तंभ निर्धारक हो और आप "sane" डेटाबेस सेटिंग्स का उपयोग कर रहे हों, इसे अनुक्रमित किया जा सकता है और इस पर आँकड़े बनाए जा सकते हैं।

मेरा मानना ​​है कि गणना किए गए कॉलम की एक अलग गणना आपकी क्वेरी के बराबर होगी।


4
बहुत बढ़िया सुझाव! जितना अधिक मैं पढ़ता हूं, उतना ही मुझे एहसास हो रहा है कि SQL सिंटैक्स और फ़ंक्शंस को जानने के बारे में कम है और शुद्ध तर्क को लागू करने के बारे में अधिक है .. काश मेरे पास 2 अपवॉट्स होते!
अष्टाध्यायी

बहुत अच्छा सुझाव है। इसने मुझे अनावश्यक कोड लिखने से परहेज किया।
अवराजित रॉय

1
क्या आप कृपया इसका उदाहरण और कोड नमूना जोड़ सकते हैं कि इसका क्या अर्थ है और इसे कैसे करना है?
jayqui

52

संपादित करें: कम-से-विश्वसनीय चेकसम-केवल क्वेरी से बदलकर मैंने ऐसा करने का एक तरीका खोजा है (SQL Server 2005 में) जो मेरे लिए बहुत अच्छी तरह से काम करता है और मुझे अपनी आवश्यकता के अनुसार (जो उन्हें जोड़कर) कई स्तंभों का उपयोग कर सकता है चेक () फ़ंक्शन। REVERSE () फ़ंक्शन विशिष्ट को अधिक विश्वसनीय बनाने के लिए इनचर्स को varchars में बदल देता है

SELECT COUNT(DISTINCT (CHECKSUM(DocumentId,DocumentSessionId)) + CHECKSUM(REVERSE(DocumentId),REVERSE(DocumentSessionId)) )
FROM DocumentOutPutItems

1
+1 अच्छा एक, सही काम करता है (जब आपके पास चेकसम को करने के लिए सही कॉलम प्रकार होते हैं ...?)
बर्नौली आईटी

8
चेकसम () जैसी हैश के साथ, एक छोटी सी संभावना है कि एक ही हैश को अलग-अलग इनपुट के लिए लौटाया जाएगा ताकि गिनती थोड़ी बहुत बंद हो जाए। हैशबाइट्स () एक भी छोटा मौका है लेकिन फिर भी शून्य नहीं है। यदि वे दो आईडीएस इंट (32 बी) थे, तो एक "दोषरहित हैश" उन्हें Id1 << 32 + Id2 जैसे बिगिन (64b) में जोड़ सकता है।
क्रॉउसेक

1
मौका इतना छोटा भी नहीं है, खासकर जब आप कॉलम संयोजन करना शुरू करते हैं (जो कि इसके लिए होना चाहिए था)। मैं इस दृष्टिकोण के बारे में उत्सुक था और एक विशेष मामले में चेकसम 10% छोटे गिनती के साथ समाप्त हुआ। यदि आप इसे थोड़ा लंबा समझते हैं, तो चेकसम केवल एक इंट रिटर्न देता है, इसलिए यदि आप एक पूर्ण Bigint रेंज चेकसम करते हैं, तो आप एक अलग गणना के साथ लगभग 2 बिलियन गुना छोटे की तुलना में वहां वास्तव में है। -1
पॉवेलर्स

डुप्लिकेट के मौके को दूर करने के लिए "REVERSE" के उपयोग को शामिल करने के लिए क्वेरी अपडेट करें
JayTee

4
क्या हम CHECKSUM से बच सकते हैं - क्या हम दोनों मूल्यों को एक साथ जोड़ सकते हैं? मुझे लगता है कि जोखिम को एक ही चीज के रूप में मानते हुए: ('वह', 'कला') == 'सुन', 'टी')। लेकिन मुझे लगता है कि इसे एक सीमांकक के साथ हल किया जा सकता है क्योंकि @APC का प्रस्ताव है (कुछ मूल्य जो या तो कॉलम में दिखाई नहीं देता है), इसलिए 'वह' कला है! = 'सुन | t' क्या एक साधारण "कंसेंटेशन" के साथ अन्य समस्याएं हैं? दृष्टिकोण?
रेड मटर

31

आपकी मौजूदा क्वेरी के बारे में ऐसा क्या है जो आपको पसंद नहीं है? यदि आप चिंतित हैं कि DISTINCTदो स्तंभों में केवल अनूठे क्रमपरिवर्तन नहीं हैं तो इसे क्यों नहीं आज़माएं?

यह निश्चित रूप से काम करता है जैसा कि आप ओरेकल में उम्मीद कर सकते हैं।

SQL> select distinct deptno, job from emp
  2  order by deptno, job
  3  /

    DEPTNO JOB
---------- ---------
        10 CLERK
        10 MANAGER
        10 PRESIDENT
        20 ANALYST
        20 CLERK
        20 MANAGER
        30 CLERK
        30 MANAGER
        30 SALESMAN

9 rows selected.


SQL> select count(*) from (
  2  select distinct deptno, job from emp
  3  )
  4  /

  COUNT(*)
----------
         9

SQL>

संपादित करें

मैं एनालिटिक्स के साथ एक अंधे गली में चला गया, लेकिन जवाब निराशाजनक था ...

SQL> select count(distinct concat(deptno,job)) from emp
  2  /

COUNT(DISTINCTCONCAT(DEPTNO,JOB))
---------------------------------
                                9

SQL>

संपादित करें २

निम्नलिखित आंकड़ों को देखते हुए उपर्युक्त समाधान प्रदान करना गलत होगा:

col1  col2
----  ----
A     AA
AA    A

तो हम एक विभाजक शामिल करने के लिए ...

select col1 + '*' + col2 from t23
/

स्पष्ट रूप से चुने हुए विभाजक को एक चरित्र, या वर्णों का सेट होना चाहिए, जो कभी भी किसी भी कॉलम में प्रकट नहीं हो सकता है।


मुझ से +1। आपके उत्तर के लिए धन्यवाद। मेरी क्वेरी ठीक काम करती है, लेकिन मैं सोच रहा था कि क्या मैं केवल एक क्वेरी (एक
उपश्रेणी

19

एकल क्वेरी के रूप में चलाने के लिए, स्तंभों को संक्षिप्त करें, फिर संक्षिप्त स्ट्रिंग के उदाहरणों की विशिष्ट गणना करें।

SELECT count(DISTINCT concat(DocumentId, DocumentSessionId)) FROM DocumentOutputItems;

MySQL में आप समवर्ती चरण के बिना एक ही काम कर सकते हैं:

SELECT count(DISTINCT DocumentId, DocumentSessionId) FROM DocumentOutputItems;

इस सुविधा का उल्लेख MySQL प्रलेखन में किया गया है:

http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_count-distinct


यह एक SQL सर्वर प्रश्न था, और आपके द्वारा पोस्ट किए गए दोनों विकल्प इस प्रश्न के निम्नलिखित उत्तरों में पहले ही उल्लेख किए गए हैं: stackoverflow.com/a/1471444/4955425 और stackoverflow.com/a/1471713/4955425
जस्टर

1
FWIW, यह लगभग PostgreSQL में काम करता है; बस अतिरिक्त कोष्ठक की आवश्यकता है:SELECT COUNT(DISTINCT (DocumentId, DocumentSessionId)) FROM DocumentOutputItems;
ijoseph

14

कैसे कुछ के बारे में:

गिनती का चयन करें (*)
से
  (चयन गिनती (*) cnt
   DocumentOutputItems से
   DocumentId, DocumentSessionId) t1 द्वारा समूह

शायद सिर्फ वही करता है जैसा कि आप पहले से ही हैं, लेकिन यह DISTINCT से बचता है।


मेरे परीक्षणों में (SET SHOWPLAN_ALL ON का उपयोग करके), इसमें एक ही निष्पादन योजना और ठीक एक ही TotalSubtreeCost
KM था।

1
मूल क्वेरी की जटिलता के आधार पर, इसे हल GROUP BYकरने के लिए वांछित उत्पादन प्राप्त करने के लिए क्वेरी परिवर्तन के लिए अतिरिक्त चुनौतियों का एक जोड़ा पेश किया जा सकता है (जैसे कि जब मूल क्वेरी पहले से थी GROUP BYया HAVINGखंड ...)
लुकास एडर

8

यहां बिना सबसिले के छोटा संस्करण दिया गया है:

SELECT COUNT(DISTINCT DocumentId, DocumentSessionId) FROM DocumentOutputItems

यह MySQL में ठीक काम करता है, और मुझे लगता है कि ऑप्टिमाइज़र के पास इसे समझने का एक आसान समय है।

संपादित करें: जाहिरा तौर पर मैंने MSSQL और MySQL को गलत समझा - इसके बारे में खेद है, लेकिन शायद यह वैसे भी मदद करता है।


6
SQL सर्वर में आपको मिलता है: Msg 102, Level 15, State 1, Line 1 गलत सिंटैक्स पास ','।
के.एम.

यही मैं सोच रहा था। मैं अगर संभव हो तो MSSQL में भी ऐसा ही काम करना चाहता हूं।
Novitzky

@Kamil Nowicki, SQL सर्वर में, आप COUNT () में केवल एक फ़ील्ड रख सकते हैं, मेरे उत्तर में मैं दिखाता हूं कि आप दो फ़ील्ड एक में समेट सकते हैं और इस दृष्टिकोण को आज़मा सकते हैं। हालाँकि, मैं बस मूल के साथ रहना चाहूँगा क्योंकि क्वेरी योजनाएँ वही समाप्त होंगी।
के.एम.

1
कृपया @JayTee जवाब में एक नज़र डालें। यह एक सम्मोहन की तरह काम करता है। count ( distinct CHECKSUM ([Field1], [Field2])
अगस्त को कस्टोडियो

5

कई (सबसे?) SQL डेटाबेस टुल्ल्स जैसे मानों के साथ काम कर सकते हैं ताकि आप बस कर सकें: SELECT COUNT(DISTINCT (DocumentId, DocumentSessionId)) FROM DocumentOutputItems; यदि आपका डेटाबेस इस बात का समर्थन नहीं करता है, तो इसे CHECKSUM या अन्य स्केलर के @ oncel-umut-turer के सुझाव के अनुसार अनुकरण किया जा सकता है जो अच्छी विशिष्टता प्रदान करता है। उदा COUNT(DISTINCT CONCAT(DocumentId, ':', DocumentSessionId))

ट्यूपल्स का एक संबंधित उपयोग INइस तरह के प्रश्नों का निष्पादन कर रहा है : SELECT * FROM DocumentOutputItems WHERE (DocumentId, DocumentSessionId) in (('a', '1'), ('b', '2'));


क्या डेटाबेस समर्थन करते हैं select count(distinct(a, b))? : डी
व्य्टिस बिविनेस

@VytenisBivainis मुझे पता है कि PostgreSQL करता है - जो संस्करण के बाद से निश्चित नहीं है।
कर्मकाज़े

3

आपकी क्वेरी में कुछ भी गलत नहीं है, लेकिन आप इसे इस तरह भी कर सकते हैं:

WITH internalQuery (Amount)
AS
(
    SELECT (0)
      FROM DocumentOutputItems
  GROUP BY DocumentId, DocumentSessionId
)
SELECT COUNT(*) AS NumberOfDistinctRows
  FROM internalQuery

3

आशा है कि यह काम मैं प्राइमा विस्टा पर लिख रहा हूं

SELECT COUNT(*) 
FROM DocumentOutputItems 
GROUP BY DocumentId, DocumentSessionId

7
इसके लिए अंतिम उत्तर देने के लिए, आपको इसे अन्य SELECT COUNT (*) FROM (...) में लपेटना होगा। अनिवार्य रूप से यह उत्तर आपको उन भिन्न मूल्यों को सूचीबद्ध करने का एक और तरीका दे रहा है, जिन्हें आप गिनना चाहते हैं। यह आपके मूल समाधान से बेहतर नहीं है।
डेव कोस्टा

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

3

मैंने इस दृष्टिकोण का उपयोग किया है और इसने मेरे लिए काम किया है।

SELECT COUNT(DISTINCT DocumentID || DocumentSessionId) 
FROM  DocumentOutputItems

मेरे मामले के लिए, यह सही परिणाम प्रदान करता है।


यह आपको दो स्तंभों के संयोजन में अलग-अलग मूल्यों की गिनती नहीं देता है। कम से कम MySQL 5.8 में नहीं।
अनवर शेख

यह प्रश्न SQL सर्वर को टैग किया गया है, और यह SQL सर्वर सिंटैक्स नहीं है
टैब Alleman

2

यदि आपके पास "DISTINCT" का केवल एक क्षेत्र है, तो आप इसका उपयोग कर सकते हैं:

SELECT COUNT(DISTINCT DocumentId) 
FROM DocumentOutputItems

और जो SET SHOWPLAN_ALL ON के साथ परीक्षण किया गया है, वही मूल योजना लौटाता है। हालाँकि आप दो क्षेत्रों का उपयोग कर रहे हैं ताकि आप कुछ पागल कोशिश कर सकें जैसे:

    SELECT COUNT(DISTINCT convert(varchar(15),DocumentId)+'|~|'+convert(varchar(15), DocumentSessionId)) 
    FROM DocumentOutputItems

लेकिन अगर NULLs शामिल हैं तो आपके पास समस्याएँ होंगी। मैं सिर्फ मूल क्वेरी के साथ रहना चाहता हूँ।


मुझ से +1। धन्यवाद, लेकिन जैसा कि आपने सुझाव दिया है, मैं अपनी क्वेरी के साथ रहूँगा। "कन्वर्ट" का उपयोग प्रदर्शन को और भी कम कर सकता है।
13 अक्टूबर को Novitzky

2

मुझे यह तब मिला जब मैंने अपने मुद्दे के लिए गोगल किया, पाया कि यदि आप DISTINCT ऑब्जेक्ट्स को गिनते हैं, तो आपको सही संख्या वापस मिल जाती है (मैं MySQL का उपयोग कर रहा हूं)

SELECT COUNT(DISTINCT DocumentID) AS Count1, 
  COUNT(DISTINCT DocumentSessionId) AS Count2
  FROM DocumentOutputItems

5
ऊपर क्वेरी क्या ओ पी (विशिष्ट लिए देख रहा था की तुलना में परिणाम का एक अलग सेट वापस आ जाएगी संयोजनों की DocumentIdऔर DocumentSessionId)। अगर ओपी MySQL और एमएस SQL ​​सर्वर का उपयोग नहीं कर रहा था तो अलेक्जेंडर केजेल ने पहले ही सही उत्तर पोस्ट कर दिया था।
एंथनी जोगेगन

1

काश MS SQL COUNT (DISTINCT A, B) जैसा भी कुछ कर पाता। लेकिन ऐसा नहीं हो सकता।

पहले जेटी के जवाब में ऐसा लगा कि कुछ परीक्षणों के बाद मुझे बू का समाधान अनोखा मूल्य बनाने में असफल रहा। एक त्वरित उदाहरण है, दोनों CHECKSUM (31,467,519) और CHECKSUM (69,1120,823) एक ही उत्तर देते हैं जो 55 है।

तब मैंने कुछ शोध किए और पाया कि Microsoft परिवर्तन पहचान के उद्देश्यों के लिए CHECKSUM का उपयोग करने की अनुशंसा नहीं करता है। कुछ मंचों में कुछ का उपयोग करने का सुझाव दिया

SELECT COUNT(DISTINCT CHECKSUM(value1, value2, ..., valueN) + CHECKSUM(valueN, value(N-1), ..., value1))

लेकिन यह भी नहीं है।

TSQL CHECKSUM conundrum में सुझाए गए अनुसार आप HASHBYTES () फ़ंक्शन का उपयोग कर सकते हैं । हालांकि यह भी अद्वितीय परिणाम नहीं लौटने का एक छोटा सा मौका है।

मैं उपयोग करने का सुझाव दूंगा

SELECT COUNT(DISTINCT CAST(DocumentId AS VARCHAR)+'-'+CAST(DocumentSessionId AS VARCHAR)) FROM DocumentOutputItems

1

इस बारे में कैसा है,

Select DocumentId, DocumentSessionId, count(*) as c 
from DocumentOutputItems 
group by DocumentId, DocumentSessionId;

इससे हमें DocumentId, और DocumentSessionId के सभी संभावित संयोजनों की गिनती मिल जाएगी


0

इससे मेरा काम बनता है। अलंकृत में:

SELECT SUM(DECODE(COUNT(*),1,1,1))
FROM DocumentOutputItems GROUP BY DocumentId, DocumentSessionId;

Jpql में:

SELECT SUM(CASE WHEN COUNT(i)=1 THEN 1 ELSE 1 END)
FROM DocumentOutputItems i GROUP BY i.DocumentId, i.DocumentSessionId;

0

मेरे पास एक समान प्रश्न था लेकिन मेरे पास जो क्वेरी थी वह मुख्य क्वेरी में तुलना डेटा के साथ एक उप-क्वेरी थी। कुछ इस तरह:

Select code, id, title, name 
(select count(distinct col1) from mytable where code = a.code and length(title) >0)
from mytable a
group by code, id, title, name
--needs distinct over col2 as well as col1

इस की जटिलताओं को नज़रअंदाज़ करते हुए, मुझे एहसास हुआ कि मैं मूल उपप्रश्न में वर्णित दोहरी उप क्वेरी के साथ उपनगर में a.code का मूल्य प्राप्त नहीं कर सकता।

Select count(1) from (select distinct col1, col2 from mytable where code = a.code...)
--this doesn't work because the sub-query doesn't know what "a" is

इसलिए अंततः मुझे लगा कि मैं धोखा दे सकता हूं, और कॉलम को जोड़ सकता हूं:

Select count(distinct(col1 || col2)) from mytable where code = a.code...

यही काम खत्म हो गया


0

यदि आप निश्चित लंबाई के डेटाटाइप्स के साथ काम कर रहे हैं, तो आप binaryइसे बहुत आसानी से और बहुत जल्दी करने के लिए डाल सकते हैं । मान लिया DocumentIdऔर DocumentSessionIdदोनों ints हैं, और इसलिए 4 बाइट लंबी हैं ...

SELECT COUNT(DISTINCT CAST(DocumentId as binary(4)) + CAST(DocumentSessionId as binary(4)))
FROM DocumentOutputItems

मेरी विशिष्ट समस्या ने मुझे विभिन्न विदेशी कुंजियों और दिनांक फ़ील्ड के अलग-अलग संयोजन SUMद्वारा विभाजित करने की आवश्यकता थी COUNT, जो कि किसी अन्य विदेशी कुंजी द्वारा समूहीकृत की जाती है और कभी-कभी कुछ मानों या कुंजियों द्वारा फ़िल्टर की जाती है। तालिका बहुत बड़ी है, और उप-क्वेरी का उपयोग करके नाटकीय रूप से क्वेरी समय में वृद्धि हुई है। और जटिलता के कारण, आँकड़े केवल एक व्यवहार्य विकल्प नहीं था। CHECKSUMसमाधान विशेष रूप से विभिन्न डेटा प्रकार का एक परिणाम के रूप में अपनी रूपांतरण में अभी तक बहुत धीमी गति से भी था, है, और मैं अपनी अविश्वसनीयता का जोखिम नहीं कर सका।

हालांकि, उपरोक्त समाधान का उपयोग करने से क्वेरी समय पर लगभग कोई वृद्धि नहीं हुई (केवल उपयोग करने की तुलना में SUM), और पूरी तरह से विश्वसनीय होना चाहिए! यह एक समान स्थिति में दूसरों की मदद करने में सक्षम होना चाहिए इसलिए मैं इसे यहां पोस्ट कर रहा हूं।


-1

आप बस दो बार काउंट फंक्शन का उपयोग कर सकते हैं।

इस मामले में, यह होगा:

SELECT COUNT (DISTINCT DocumentId), COUNT (DISTINCT DocumentSessionId) 
FROM DocumentOutputItems

प्रश्न में इसकी आवश्यकता नहीं है, यह प्रत्येक कॉलम के लिए अलग-अलग अलग-अलग गणना करता है
नवराम

-1

यह कोड 2 मापदंडों पर अलग-अलग का उपयोग करता है और उन विशिष्ट मान पंक्ति गणना के लिए विशिष्ट पंक्तियों की संख्या प्रदान करता है। इसने मेरे लिए MySQL में एक आकर्षण की तरह काम किया।

select DISTINCT DocumentId as i,  DocumentSessionId as s , count(*) 
from DocumentOutputItems   
group by i ,s;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.