विभाजन समारोह () DISTINCT का उपयोग कर संभव है


88

मैं निम्नलिखित न्यूमूज़र की कुल संख्या प्राप्त करने के लिए निम्नलिखित लिखने की कोशिश कर रहा हूँ, जैसे:

NumUsers = COUNT(DISTINCT [UserAccountKey]) OVER (PARTITION BY [Mth])

प्रबंधन स्टूडियो इस बारे में बहुत खुश नहीं लगता है। DISTINCTकीवर्ड को हटाते समय त्रुटि गायब हो जाती है , लेकिन तब यह एक अलग गिनती नहीं होगी।

DISTINCTविभाजन कार्यों के भीतर संभव नहीं प्रतीत होता है। मैं अलग-अलग गिनती खोजने के बारे में कैसे जाऊँ? क्या मैं एक अधिक पारंपरिक विधि का उपयोग करता हूं जैसे कि सहसंबंधित उपशम?

इसे थोड़ा आगे बढ़ाते हुए, हो सकता है कि ये OVERकार्य ओरेकल के अलग-अलग तरीके से काम करते हों , जिनका उपयोग इनका उपयोग SQL-Serverचल रहे योगों की गणना करने में नहीं किया जा सकता है ।

मैंने यहां SQLfiddle पर एक लाइव उदाहरण जोड़ा है जहां मैं एक रनिंग कुल की गणना करने के लिए एक विभाजन फ़ंक्शन का उपयोग करने का प्रयास करता हूं।


2
COUNTके ORDER BYबजाय PARTITION BY2008 में बीमार परिभाषित किया गया है। मुझे आश्चर्य है कि यह आपको यह बिल्कुल दे रहा है। प्रति प्रलेखन , आप एक के लिए अनुमति नहीं कर रहे हैं ORDER BYएक समग्र समारोह के लिए।
डेमियन_इन_उन्नीवर

हाँ - लगता है कि मैं कुछ ओरेकल कार्यक्षमता के साथ भ्रमित हो रहा हूं; ये रनिंग योग और रनिंग काउंट थोड़े ज्यादा शामिल होंगे
Whytheq

जवाबों:


177

उपयोग करने का एक बहुत ही सरल उपाय है dense_rank()

dense_rank() over (partition by [Mth] order by [UserAccountKey]) 
+ dense_rank() over (partition by [Mth] order by [UserAccountKey] desc) 
- 1

यह आपको वही देगा जो आप पूछ रहे थे: प्रत्येक माह के भीतर अलग-अलग उपयोगकर्ताआकाउंट की संख्या।


23
इसके साथ सावधान रहने वाली एक बात dense_rank()यह है कि यह NULLs की गिनती करेगा जबकि COUNT(field) OVERऐसा नहीं है। मैं इसे इस वजह से अपने समाधान में नियोजित नहीं कर सकता लेकिन मुझे अभी भी लगता है कि यह काफी चतुर है।
bf2020

1
लेकिन मैं प्रत्येक वर्ष के महीनों में विभिन्न उपयोगकर्ताकाउंटरों की कुल संख्या की तलाश कर रहा हूं: निश्चित नहीं कि यह कैसे उत्तर देता है?
Whytheq

4
@ bf2020, अगर वहाँ हो सकता है NULLमें मान UserAccountKey, तो आप इस अवधि जोड़ने की जरूरत है: -MAX(CASE WHEN UserAccountKey IS NULL THEN 1 ELSE 0 END) OVER (PARTITION BY Mth)। आइडिया नीचे दिए गए LarsRönnbäck के जवाब से लिया गया है। अनिवार्य रूप से, अगर UserAccountKeyहै NULLमूल्यों, आप अतिरिक्त घटाना करने की जरूरत है 1परिणाम से, क्योंकि DENSE_RANKमायने रखता है NULLs।
व्लादिमीर बारानोव

1
@steelele शुक्रिया यार, आपने मेरे दिमाग को उड़ा दिया और मेरी समस्या हल कर दी
हेनरिक डोनाती

यहाँ इस dense_rankसमाधान का उपयोग करने की चर्चा है जब विंडो फ़ंक्शन में एक फ्रेम है। SQL सर्वर dense_rankएक विंडो फ्रेम के साथ उपयोग करने की अनुमति नहीं देता है: stackoverflow.com/questions/63527035/…
K4M

6

Necromancing:

यह DENSE_RANK के माध्यम से MAX के साथ भागीदारी पर COIST DISTINCT का अनुकरण करने के लिए सरल रूप से सरल है:

;WITH baseTable AS
(
    SELECT 'RM1' AS RM, 'ADR1' AS ADR
    UNION ALL SELECT 'RM1' AS RM, 'ADR1' AS ADR
    UNION ALL SELECT 'RM2' AS RM, 'ADR1' AS ADR
    UNION ALL SELECT 'RM2' AS RM, 'ADR2' AS ADR
    UNION ALL SELECT 'RM2' AS RM, 'ADR2' AS ADR
    UNION ALL SELECT 'RM2' AS RM, 'ADR3' AS ADR
    UNION ALL SELECT 'RM3' AS RM, 'ADR1' AS ADR
    UNION ALL SELECT 'RM2' AS RM, 'ADR1' AS ADR
    UNION ALL SELECT 'RM3' AS RM, 'ADR1' AS ADR
    UNION ALL SELECT 'RM3' AS RM, 'ADR2' AS ADR
)
,CTE AS
(
    SELECT RM, ADR, DENSE_RANK() OVER(PARTITION BY RM ORDER BY ADR) AS dr 
    FROM baseTable
)
SELECT
     RM
    ,ADR

    ,COUNT(CTE.ADR) OVER (PARTITION BY CTE.RM ORDER BY ADR) AS cnt1 
    ,COUNT(CTE.ADR) OVER (PARTITION BY CTE.RM) AS cnt2 
    -- Not supported
    --,COUNT(DISTINCT CTE.ADR) OVER (PARTITION BY CTE.RM ORDER BY CTE.ADR) AS cntDist
    ,MAX(CTE.dr) OVER (PARTITION BY CTE.RM ORDER BY CTE.RM) AS cntDistEmu 
FROM CTE

नोट:
यह मान लिया जाता है कि विचाराधीन क्षेत्र गैर-अशक्त क्षेत्र हैं।
यदि फ़ील्ड में एक या अधिक NULL-प्रविष्टियाँ हैं, तो आपको 1 को घटाने की आवश्यकता है।


5

मैं एक समाधान का उपयोग करता हूं जो ऊपर डेविड के समान है , लेकिन एक अतिरिक्त मोड़ के साथ अगर कुछ पंक्तियों को गिनती से बाहर रखा जाना चाहिए। यह मानता है कि [UserAccountKey] कभी भी अशक्त नहीं है।

-- subtract an extra 1 if null was ranked within the partition,
-- which only happens if there were rows where [Include] <> 'Y'
dense_rank() over (
  partition by [Mth] 
  order by case when [Include] = 'Y' then [UserAccountKey] else null end asc
) 
+ dense_rank() over (
  partition by [Mth] 
  order by case when [Include] = 'Y' then [UserAccountKey] else null end desc
)
- max(case when [Include] = 'Y' then 0 else 1 end) over (partition by [Mth])
- 1

एक विस्तारित उदाहरण के साथ एक SQL फिडेल यहां पाया जा सकता है।


1
आपके विचार का उपयोग मूल सूत्र बनाने के लिए किया जा सकता है ( [Include]उस जटिलता के बिना जब आप अपने उत्तर के बारे में बात कर रहे हों) dense_rank()जब काम हो UserAccountKeyसकता है NULL। इस शब्द को सूत्र में जोड़ें -MAX(CASE WHEN UserAccountKey IS NULL THEN 1 ELSE 0 END) OVER (PARTITION BY Mth):।
व्लादिमीर बारानोव

5

मुझे लगता है कि SQL-Server 2008R2 में ऐसा करने का एकमात्र तरीका सहसंबंधित उप-वर्ग या बाहरी अनुप्रयोग का उपयोग करना है:

SELECT  datekey,
        COALESCE(RunningTotal, 0) AS RunningTotal,
        COALESCE(RunningCount, 0) AS RunningCount,
        COALESCE(RunningDistinctCount, 0) AS RunningDistinctCount
FROM    document
        OUTER APPLY
        (   SELECT  SUM(Amount) AS RunningTotal,
                    COUNT(1) AS RunningCount,
                    COUNT(DISTINCT d2.dateKey) AS RunningDistinctCount
            FROM    Document d2
            WHERE   d2.DateKey <= document.DateKey
        ) rt;

यह SQL-Server 2012 में आपके द्वारा सुझाए गए सिंटैक्स का उपयोग करके किया जा सकता है :

SELECT  datekey,
        SUM(Amount) OVER(ORDER BY DateKey) AS RunningTotal
FROM    document

हालाँकि, DISTINCTअभी भी उपयोग की अनुमति नहीं है, इसलिए यदि DISTINCT की आवश्यकता है और / या यदि उन्नयन एक विकल्प नहीं है, तो मुझे लगता OUTER APPLYहै कि यह आपका पसंदीदा विकल्प है


शांत धन्यवाद। मुझे यह SO उत्तर मिला जो OUTER APPLY विकल्प की सुविधा देता है जिसे मैं प्रयास करूंगा। क्या आपने उस उत्तर में लूपिंग अपडेट को देखा है ... यह बहुत दूर है और स्पष्ट रूप से तेज है। 2012 में जीवन आसान हो जाएगा - क्या यह एक सीधी ओरेकल कॉपी है?
Whytheq
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.