why*_*heq 69 sql t-sql sql-server sql-server-2008-r2 sql-server-2014
我正在尝试编写以下内容,以便获得不同的NumUsers,如下所示:
NumUsers = COUNT(DISTINCT [UserAccountKey]) OVER (PARTITION BY [Mth])
Run Code Online (Sandbox Code Playgroud)
管理工作室对此并不感到高兴.当我删除DISTINCT关键字时,错误消失,但它不会是一个独特的计数.
DISTINCT在分区函数中似乎不可能.我如何寻找独特的计数?我是否使用更传统的方法,例如相关子查询?
进一步研究一下,也许这些OVER函数与Oracle的工作方式不同,它们不能用于SQL-Server计算运行总计.
我在SQLfiddle上添加了一个实例,我尝试使用分区函数来计算运行总计.
小智 142
有一个非常简单的解决方案 dense_rank()
dense_rank() over (partition by [Mth] order by [UserAccountKey])
+ dense_rank() over (partition by [Mth] order by [UserAccountKey] desc)
- 1
Run Code Online (Sandbox Code Playgroud)
这将为您提供您所要求的内容:每个月内不同UserAccountKeys的数量.
死灵法术:
通过 DENSE_RANK 模拟 COUNT DISTINCT over PARTITION BY 和 MAX 相对简单:
;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
Run Code Online (Sandbox Code Playgroud)
注意:
这假设有问题的字段是不可为空的字段。
如果字段中有一个或多个 NULL 条目,则需要减 1。
我认为在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;
Run Code Online (Sandbox Code Playgroud)
这可以使用您建议的语法在SQL-Server 2012中完成:
SELECT datekey,
SUM(Amount) OVER(ORDER BY DateKey) AS RunningTotal
FROM document
Run Code Online (Sandbox Code Playgroud)
但是,DISTINCT仍然不允许使用,因此如果需要DISTINCT和/或如果升级不是一个选项,那么我认为这OUTER APPLY是您的最佳选择
我使用的解决方案与上述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
Run Code Online (Sandbox Code Playgroud)