विभाजन पर एसक्यूएल की गिनती अलग है


10

मेरे पास दो स्तंभों वाली एक तालिका है, मैं Col_A (कंडीशंड द्वारा) Col_A पर अलग-अलग मानों को गिनना चाहता हूं।

मेरी टेबल

Col_A | Col_B 
A     | 1
A     | 1
A     | 2
A     | 2
A     | 2
A     | 3
b     | 4
b     | 4
b     | 5

अपेक्षित परिणाम

Col_A   | Col_B | Result
A       | 1     | 3
A       | 1     | 3
A       | 2     | 3
A       | 2     | 3
A       | 2     | 3
A       | 3     | 3
b       | 4     | 2
b       | 4     | 2
b       | 5     | 2

मैंने निम्नलिखित कोड की कोशिश की

select *, 
count (distinct col_B) over (partition by col_A) as 'Result'
from MyTable

गिनती (अलग col_B) काम नहीं कर रही है। मैं अलग-अलग मूल्यों को गिनने के लिए गिनती फ़ंक्शन को कैसे लिख सकता हूं?

जवाबों:


18

इस तरह से मैं यह करूँगा:

SELECT      *
FROM        #MyTable AS mt
CROSS APPLY (   SELECT COUNT(DISTINCT mt2.Col_B) AS dc
                FROM   #MyTable AS mt2
                WHERE  mt2.Col_A = mt.Col_A
                -- GROUP BY mt2.Col_A 
            ) AS ca;

GROUP BYखंड निरर्थक प्रश्न में उपलब्ध कराए गए आंकड़ों में दिया जाता है, लेकिन आप एक बेहतर कार्य योजना लागू करके दे सकते हैं। अनुवर्ती प्रश्न देखें और एक क्रॉस आवेदन बाहरी जुड़ाव पैदा करता है

यदि आप उस सुविधा को SQL सर्वर में शामिल करना चाहते हैं, तो फ़ीडबैक साइट पर समग्र कार्यों के लिए DISTINCT क्लाज - OVER क्लॉज एन्हांसमेंट अनुरोध के लिए मतदान करने पर विचार करें ।


6

आप इसका उपयोग करके अनुकरण कर सकते हैं dense_rank, और फिर प्रत्येक विभाजन के लिए अधिकतम रैंक चुन सकते हैं:

select col_a, col_b, max(rnk) over (partition by col_a)
from (
    select col_a, col_b
        , dense_rank() over (partition by col_A order by col_b) as rnk 
    from #mytable
) as t    

जैसा भी col_bपरिणाम हो, आपको किसी भी नल को बाहर करने की आवश्यकता होगी COUNT(DISTINCT)


6

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

SELECT
  Col_A,
  Col_B,
  DistinctCount = DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B ASC )
                + DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B DESC)
                - 1
                - CASE COUNT(Col_B) OVER (PARTITION BY Col_A)
                  WHEN COUNT(  *  ) OVER (PARTITION BY Col_A)
                  THEN 0
                  ELSE 1
                  END
FROM
  dbo.MyTable
;

गणना का मुख्य हिस्सा यह है (और मैं सबसे पहले यह नोट करना चाहूंगा कि विचार मेरा नहीं है, मैंने इस चाल के बारे में कहीं और सीखा है):

  DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B ASC )
+ DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B DESC)
- 1

इस अभिव्यक्ति का उपयोग बिना किसी परिवर्तन के किया जा सकता है यदि मूल्यों की Col_Bगारंटी है कि कभी भी अशक्त नहीं है। यदि स्तंभ में नल हो सकते हैं, हालांकि, आपको इसके लिए खाते की आवश्यकता है, और यह वही है जो CASEअभिव्यक्ति के लिए है। यह प्रति विभाजन Col_Bमानों की संख्या के साथ विभाजन की पंक्तियों की संख्या की तुलना करता है । यदि संख्या भिन्न होती है, तो इसका मतलब है कि कुछ पंक्तियों में एक अशक्त है Col_B, इसलिए, प्रारंभिक गणना ( DENSE_RANK() ... + DENSE_RANK() - 1) को 1 से कम करने की आवश्यकता है।

ध्यान दें कि क्योंकि - 1मूल सूत्र का हिस्सा है, मैंने इसे उसी तरह छोड़ने का विकल्प चुना। हालांकि, इसे वास्तव में CASEअभिव्यक्ति में शामिल किया जा सकता है , संपूर्ण समाधान को कम बदसूरत बनाने के निरर्थक प्रयास में:

SELECT
  Col_A,
  Col_B,
  DistinctCount = DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B ASC )
                + DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B DESC)
                - CASE COUNT(Col_B) OVER (PARTITION BY Col_A)
                  WHEN COUNT(  *  ) OVER (PARTITION BY Col_A)
                  THEN 1
                  ELSE 2
                  END
FROM
  dbo.MyTable
;

dbfiddle लोगोDb <> fiddle.uk पर इस लाइव डेमो का उपयोग समाधान के दोनों रूपों का परीक्षण करने के लिए किया जा सकता है।


2
create table #MyTable (
Col_A varchar(5),
Col_B int
)

insert into #MyTable values ('A',1)
insert into #MyTable values ('A',1)
insert into #MyTable values ('A',2)
insert into #MyTable values ('A',2)
insert into #MyTable values ('A',2)
insert into #MyTable values ('A',3)

insert into #MyTable values ('B',4)
insert into #MyTable values ('B',4)
insert into #MyTable values ('B',5)


;with t1 as (

select t.Col_A,
       count(*) cnt
 from (
    select Col_A,
           Col_B,
           count(*) as ct
      from #MyTable
     group by Col_A,
              Col_B
  ) t
  group by t.Col_A
 )

select a.*,
       t1.cnt
  from #myTable a
  join t1
    on a.Col_A = t1.Col_a

1

वैकल्पिक यदि आप सहसंबद्ध उप-क्षेत्रों (एरिक डार्लिंग का उत्तर) और CTE (मेरी तरह kevinnwhat के उत्तर) से एलर्जी हो।

ध्यान रखें कि जब नल मिश्रण में फेंक दिए जाते हैं, तो इनमें से कोई भी काम नहीं कर सकता है कि आप उन्हें कैसे पसंद करेंगे। (लेकिन उन्हें स्वाद के लिए संशोधित करना काफी सरल है)

साधारण मामला:

--ignore the existence of nulls
SELECT [mt].*, [Distinct_B].[Distinct_B]
FROM #MyTable AS [mt]

INNER JOIN(
    SELECT [Col_A], COUNT(DISTINCT [Col_B]) AS [Distinct_B]
    FROM #MyTable
    GROUP BY [Col_A]
) AS [Distinct_B] ON
    [mt].[Col_A] = [Distinct_B].[Col_A]
;

ऊपर के रूप में भी, लेकिन अशक्त हैंडलिंग के लिए क्या बदलना है पर टिप्पणी के साथ:

--customizable null handling
SELECT [mt].*, [Distinct_B].[Distinct_B]
FROM #MyTable AS [mt]

INNER JOIN(
    SELECT 

    [Col_A],

    (
        COUNT(DISTINCT [Col_B])
        /*
        --uncomment if you also want to count Col_B NULL
        --as a distinct value
        +
        MAX(
            CASE
                WHEN [Col_B] IS NULL
                THEN 1
                ELSE 0
            END
        )
        */
    )
    AS [Distinct_B]

    FROM #MyTable
    GROUP BY [Col_A]
) AS [Distinct_B] ON
    [mt].[Col_A] = [Distinct_B].[Col_A]
/*
--uncomment if you also want to include Col_A when it's NULL
OR
([mt].[Col_A] IS NULL AND [Distinct_B].[Col_A] IS NULL)
*/
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.