我正在尝试编写以下内容,以便获得不同的NumUsers,如下所示:
NumUsers = COUNT(DISTINCT [UserAccountKey]) OVER (PARTITION BY [Mth])
管理工作室对此并不感到高兴。我删除DISTINCT
关键字时错误消失了,但它不会是一个明显的计数。
DISTINCT
。
我如何寻找独特的计数?我是否使用更多传统方法,例如相关子查询?
进一步研究一下,这些OVER
函数可能与Oracle在SQL-Server
中无法用于计算运行总计的方式不同。
我在SQLfiddle添加了一个实例,我尝试使用分区函数计算运行总数。
答案 0 :(得分:130)
dense_rank() over (partition by [Mth] order by [UserAccountKey])
+ dense_rank() over (partition by [Mth] order by [UserAccountKey] desc)
- 1
这将为您提供您所要求的内容:每个月内不同UserAccountKeys的数量。
答案 1 :(得分: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
是您的最佳选择
答案 2 :(得分:4)
我使用的解决方案类似于上面David的解决方案,但如果应从计数中排除某些行,则会额外扭曲。这假设[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
答案 3 :(得分:3)
Necromancing:
使用MAX通过DENSE_RANK模拟COTI 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