使用 T-SQL 的 n 天活跃用户的滚动计数 DISTINCT
Rolling COUNT DISTINCT of n-day active users using T-SQL
我正在使用 T-SQL 计算 7 天活跃用户。我使用了以下代码:
SELECT
*,
COUNT(DISTINCT [UserID]) OVER (
PARTITION BY [HospitalID], [HospitalName], [Device]
ORDER BY [Date]
ROWS 7 PRECEDING
) AS [7-Day Active Users]
FROM UserActivity
ORDER BY [HospitalID], [HospitalName], [Device], [Date]
有人告诉我 Use of DISTINCT is not allowed with the OVER clause
。
UserActivity
是具有列 HospitalID
、HospitalName
、Device
(phone 或 tablet)、Date
和 UserID
(可以为 NULL)。为了让事情变得更简单,我填补了使 Date
连续的日期之间的空白,这样我就可以放心地使用 ROWS 7 PRECEDING
。我在网上做了很多搜索,发现大多数解决方案要么使用其他类型的 SQL(这在我的情况下是不可能的),要么使用不支持移动 window 的 DENSE_RANK
函数.解决我的问题的正确且希望更简单、简洁的方法是什么?
很抱歉看到 COUNT DISTINCT
在那种类型的 SQL 中不受支持...我以前不知道。尤其是在您费尽心力解决日期之间的差距之后!
我使用 Rasgo 生成了 SQL -- 所以这不会直接在你的版本中工作(用 Snowflake 测试过),但我认为只要你修复它就会工作DATEADD
函数。每个 RDBMS 似乎 DATEADD
都不同,似乎。
这里的一般概念是使用 WHERE
子句中的 range join
条件将数据连接到自身。
幸运的是,这应该对您有用,而无需先修复日期之间的差距。
WITH BASIC_OFFSET_7DAY AS (
SELECT
A.HOSPITALNAME,
A.HOSPITALID,
A.DEVICE,
A.DATE,
COUNT(DISTINCT B.USERID) as COUNT_DISTINCT_USERID_PAST7DAY,
COUNT(1) AS AGG_ROW_COUNT
FROM
UserActivity A
INNER JOIN UserActivity B ON A.HOSPITALNAME = B.HOSPITALNAME
AND A.HOSPITALID = B.HOSPITALID
AND A.DEVICE = B.DEVICE
WHERE
B.DATE >= DATEADD(day, -7, A.DATE)
AND B.DATE <= A.DATE
GROUP BY
A.HOSPITALNAME,
A.HOSPITALID,
A.DEVICE,
A.DATE
)
SELECT
src.*,
BASIC_OFFSET_7DAY.COUNT_DISTINCT_USERID_PAST7DAY
FROM
UserActivity src
LEFT OUTER JOIN BASIC_OFFSET_7DAY ON BASIC_OFFSET_7DAY.DATE = src.DATE
AND BASIC_OFFSET_7DAY.HOSPITALNAME = src.HOSPITALNAME
AND BASIC_OFFSET_7DAY.HOSPITALID = src.HOSPITALID
AND BASIC_OFFSET_7DAY.DEVICE = src.DEVICE
让我知道结果如何,如果不起作用,我会帮助您。
编辑:对于那些尝试这样做并卡住的人来说,一个常见的错误(我自己在手动执行此操作时犯的错误)是要特别注意 COUNT(DISTINCT(B.col )) 而不是 A.col。当我使用 Rasgo 生成 SQL 来检查自己时,我发现了我的错误。希望这篇笔记对以后犯同样错误的人有所帮助!
我正在使用 T-SQL 计算 7 天活跃用户。我使用了以下代码:
SELECT
*,
COUNT(DISTINCT [UserID]) OVER (
PARTITION BY [HospitalID], [HospitalName], [Device]
ORDER BY [Date]
ROWS 7 PRECEDING
) AS [7-Day Active Users]
FROM UserActivity
ORDER BY [HospitalID], [HospitalName], [Device], [Date]
有人告诉我 Use of DISTINCT is not allowed with the OVER clause
。
UserActivity
是具有列 HospitalID
、HospitalName
、Device
(phone 或 tablet)、Date
和 UserID
(可以为 NULL)。为了让事情变得更简单,我填补了使 Date
连续的日期之间的空白,这样我就可以放心地使用 ROWS 7 PRECEDING
。我在网上做了很多搜索,发现大多数解决方案要么使用其他类型的 SQL(这在我的情况下是不可能的),要么使用不支持移动 window 的 DENSE_RANK
函数.解决我的问题的正确且希望更简单、简洁的方法是什么?
很抱歉看到 COUNT DISTINCT
在那种类型的 SQL 中不受支持...我以前不知道。尤其是在您费尽心力解决日期之间的差距之后!
我使用 Rasgo 生成了 SQL -- 所以这不会直接在你的版本中工作(用 Snowflake 测试过),但我认为只要你修复它就会工作DATEADD
函数。每个 RDBMS 似乎 DATEADD
都不同,似乎。
这里的一般概念是使用 WHERE
子句中的 range join
条件将数据连接到自身。
幸运的是,这应该对您有用,而无需先修复日期之间的差距。
WITH BASIC_OFFSET_7DAY AS (
SELECT
A.HOSPITALNAME,
A.HOSPITALID,
A.DEVICE,
A.DATE,
COUNT(DISTINCT B.USERID) as COUNT_DISTINCT_USERID_PAST7DAY,
COUNT(1) AS AGG_ROW_COUNT
FROM
UserActivity A
INNER JOIN UserActivity B ON A.HOSPITALNAME = B.HOSPITALNAME
AND A.HOSPITALID = B.HOSPITALID
AND A.DEVICE = B.DEVICE
WHERE
B.DATE >= DATEADD(day, -7, A.DATE)
AND B.DATE <= A.DATE
GROUP BY
A.HOSPITALNAME,
A.HOSPITALID,
A.DEVICE,
A.DATE
)
SELECT
src.*,
BASIC_OFFSET_7DAY.COUNT_DISTINCT_USERID_PAST7DAY
FROM
UserActivity src
LEFT OUTER JOIN BASIC_OFFSET_7DAY ON BASIC_OFFSET_7DAY.DATE = src.DATE
AND BASIC_OFFSET_7DAY.HOSPITALNAME = src.HOSPITALNAME
AND BASIC_OFFSET_7DAY.HOSPITALID = src.HOSPITALID
AND BASIC_OFFSET_7DAY.DEVICE = src.DEVICE
让我知道结果如何,如果不起作用,我会帮助您。
编辑:对于那些尝试这样做并卡住的人来说,一个常见的错误(我自己在手动执行此操作时犯的错误)是要特别注意 COUNT(DISTINCT(B.col )) 而不是 A.col。当我使用 Rasgo 生成 SQL 来检查自己时,我发现了我的错误。希望这篇笔记对以后犯同样错误的人有所帮助!