假设我在SQL Server 2012中有一个表UserActivity,其中包含两列:
- 活动日期时间
- 用户标识
我想计算 30 天内每天具有任何活动的不同用户数(我的月活跃用户数)。(所以我有一个 30 天的窗口,一次增加一天。如何使用 SQL Server 中的窗口函数有效地执行此操作?
输出如下所示:
Date,NumberActiveUsersInPrevious30Days
01-01-2010,13567
01-02-2010,14780
01-03-2010,13490
01-04-2010,15231
01-05-2010,15321
01-06-2010,14513
...
SQL Server 不支持将COUNT(DISTINCT ... ) OVER ()
或数值 ( 30 PRECEDING
) 与RANGE
结合使用
我不会费心试图强迫窗口函数这样做。由于COUNT(DISTINCT UserID)
要求,它总是必须重新检查每个日期的整个 30 天窗口。
您可以创建一个日历表,每个日期都有一行,并使用
SELECT C.Date,
NumberActiveUsersInPrevious30Days
FROM Calendar C
CROSS APPLY (SELECT COUNT(DISTINCT UserID)
FROM UserActivity
WHERE ActivityDateTime >= DATEADD(DAY, -30, C.[Date])
AND ActivityDateTime < C.[Date]) CA(NumberActiveUsersInPrevious30Days)
WHERE C.Date BETWEEN '2010-01-01' AND '2010-01-06'
选项 1:对于(同时)每天循环,并为每个向后选择 30 天(显然很慢)。
选项 2:一个单独的表,每天有一行,并在原始表上连接(同样很慢)。
选项 3:递归 CTE 或存储过程(仍然没有做得更好)。
选项 4:对于(同时)与游标组合的循环(高效,但需要一些高级 SQL 知识)。使用此解决方案,您将按顺序逐步浏览每一天和每一行,并跟踪平均值(您需要某种环绕数组来知道当一天超出范围时要减去的值)。
选项5:选项3在通用/脚本编程语言(C++/Java/PHP)(很容易做到这些语言之一的基本知识,高效)。
一些相关问题。