J'essaie d'écrire ce qui suit afin d'obtenir un total cumulé d'utilisateurs NumU distincts, comme ceci:
NumUsers = COUNT(DISTINCT [UserAccountKey]) OVER (PARTITION BY [Mth])
Le studio de gestion ne semble pas trop heureux à ce sujet. L'erreur disparaît lorsque je supprime le mot clé DISTINCT
, mais il ne s'agira pas d'un compte distinct.
DISTINCT
ne semble pas être possible dans les fonctions de partition. Comment puis-je trouver le nombre distinct? Est-ce que j'utilise une méthode plus traditionnelle telle qu'une sous-requête corrélée?
En regardant cela un peu plus loin, peut-être que ces fonctions OVER
fonctionnent différemment de Oracle car elles ne peuvent pas être utilisées dans SQL-Server
pour calculer les totaux cumulés.
J'ai ajouté un exemple en direct ici sur SQLfiddle où je tente d'utiliser une fonction de partition pour calculer un total cumulé.
Il existe une solution très simple utilisant dense_rank()
dense_rank() over (partition by [Mth] order by [UserAccountKey])
+ dense_rank() over (partition by [Mth] order by [UserAccountKey] desc)
- 1
Cela vous donnera exactement ce que vous demandiez: le nombre de UserAccountKeys distincts au cours de chaque mois.
Je pense que la seule façon de faire cela dans SQL-Server 2008R2 est d'utiliser une sous-requête corrélée, ou une application externe:
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;
Cela peut être fait dans SQL-Server 2012 en utilisant la syntaxe que vous avez suggérée:
SELECT datekey,
SUM(Amount) OVER(ORDER BY DateKey) AS RunningTotal
FROM document
Cependant, l'utilisation de DISTINCT
n'est toujours pas autorisée. Par conséquent, si DISTINCT est requis et/ou si la mise à niveau n'est pas une option, alors je pense que OUTER APPLY
est votre meilleure option
J'utilise une solution similaire à celle de David ci-dessus, mais avec une torsion supplémentaire si certaines lignes doivent être exclues du décompte. Cela suppose que [UserAccountKey] n'est jamais null.
-- 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
Nécromancie:
Il est relativement simple d'émuler un COUNT DISTINCT sur PARTITION BY avec MAX via DENSE_RANK:
;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