2016-08-04 1 views
1

Je voudrais un compte distinct en cours d'exécution avec une partition par année pour les données suivantes:Courir avec Count Distinct une partition

DROP TABLE IF EXISTS #FACT; 
CREATE TABLE #FACT("Year" INT,"Month" INT, "Acc" varchar(5)); 
INSERT INTO #FACT 
    values 
     (2015, 1, 'A'), 
     (2015, 1, 'B'), 
     (2015, 1, 'B'), 
     (2015, 1, 'C'), 
     (2015, 2, 'D'), 
     (2015, 2, 'E'), 
     (2015, 3, 'E'), 
     (2016, 1, 'A'), 
     (2016, 1, 'A'), 
     (2016, 2, 'B'), 
     (2016, 2, 'C'); 
SELECT * FROM #FACT;  

Les rendements suivants la bonne réponse, mais est-il une façon plus concise qui est aussi performant?

WITH 
dnsRnk AS 
(
    SELECT 
     "Year" 
     , "Month" 
     , DenseR = DENSE_RANK() OVER(PARTITION BY "Year", "Month" ORDER BY "Acc") 
    FROM #FACT 
), 
mxPerMth AS 
(
    SELECT 
     "Year" 
     , "Month" 
     , RunningTotal = MAX(DenseR) 
    FROM dnsRnk 
    GROUP BY 
     "Year" 
     , "Month" 
) 
SELECT 
    "Year" 
    , "Month" 
    , X = SUM(RunningTotal) OVER (PARTITION BY "Year" ORDER BY "Month") 
FROM mxPerMth 
ORDER BY 
    "Year" 
    , "Month"; 

Les rendements ci-dessus les éléments suivants - la réponse doit également revenir exactement la même table:

enter image description here

+0

Pouvez-vous modifier la question et de montrer la les résultats souhaités? –

+0

@GordonLinoff fourni maintenant: la réponse devrait retourner la même – whytheq

Répondre

1

Si vous voulez un compte courant des comptes distincts:

select f.*, 
     sum(case when seqnum = 1 then 1 else 0 end) over (partition by year order by month) as cume_distinct_acc 
from (select f.*, 
      row_number() over (partition by account order by year, month) as seqnum 
     from #fact f 
    ) f; 

Cette compte chaque compte pendant le premier mois quand il apparaît.

EDIT:

Oups. Ce qui précède ne se cumule pas par année et par mois et recommence ensuite pour chaque année. Voici la solution correcte:

select yyyy, mm, 
     sum(sum(case when seqnum = 1 then 1 else 0 end) 
     ) over (partition by year order by month) as cume_distinct_acc 
from (select f.*, 
      row_number() over (partition by account, year order by month) as seqnum 
     from #fact f 
    ) f 
group by year, month 
order by year, month; 

Et, SQL Fiddle ne fonctionne pas, mais ce qui suit est un exemple:

with FACT as (
    SELECT yyyy, mm, account 
    FROM (values 
     (2015, 1, 'A'), 
     (2015, 1, 'B'), 
     (2015, 1, 'B'), 
     (2015, 1, 'C'), 
     (2015, 2, 'D'), 
     (2015, 2, 'E'), 
     (2015, 3, 'E'), 
     (2016, 1, 'A'), 
     (2016, 1, 'A'), 
     (2016, 2, 'B'), 
     (2016, 2, 'C')) v(yyyy, mm, account) 
    ) 
select yyyy, mm, 
     sum(sum(case when seqnum = 1 then 1 else 0 end)) over (partition by yyyy order by mm) as cume_distinct_acc 
from (select f.*, 
      row_number() over (partition by account, yyyy order by mm) as seqnum 
     from fact f 
    ) f 
group by yyyy, mm 
order by yyyy, mm; 
+0

Je pense que c'est une bonne approche mais actuellement il ne retourne pas le même résultat que le script dans la question: les résultats devraient être les mêmes – whytheq

1

Demo Here:

;with cte 
as 
(select yearr,monthh,count(distinct acc) as cnt from #fact 
group by yearr,monthh 
) 
select yearr,monthh, 
sum(cnt) over (Partition by yearr order by yearr,monthh rows unbounded preceding) as x 
from cte 
+0

est-ce quelque chose pris en charge après SQL Server 2012 ? –

+0

Il prend en charge de SQLServer 2012, si c'est ce que vous demandez – TheGameiswar

+0

Essayé de l'utiliser, m'a donné une erreur: 'Syntaxe incorrecte près de 'preceeding' –