分区函数COUNT()OVER可能使用DISTINCT

我正在尝试编写以下代码以获得一个不同的NumUsers,如下所示:

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

pipe理工作室似乎不太高兴。 当我删除DISTINCT关键字时,该错误消失,但不会是一个明显的计数。

DISTINCT在分区function中似乎不可能。 我怎么去find不同的数字? 我是否使用更传统的方法,如相关的子查询?

再仔细看看这些,可能这些OVER函数与Oracle的工作方式不同,它们不能在SQL-Server用来计算运行总数。

我在SQLfiddle上添加了一个实例,我尝试使用分区函数来计算运行总数。

有一个非常简单的解决scheme,使用dense_rank()

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

这将会给你正是你所要求的:每个月内不同UserAccountKeys的数量。

我认为在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是你最好的select

我使用的解决scheme与上面David的解决scheme类似,但是如果某些行应该从计数中排除,则需要额外的转换。 这假定[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小提琴可以在这里find。

Necromancing:

使用MAX通过DENSE_RANK模拟COUNT DISTINCT而不是使用PARTITION BY来执行相对简单:

 ;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