提问人:C93H 提问时间:11/2/2023 最后编辑:SelVaziC93H 更新时间:11/2/2023 访问量:78
计算 7 天内的活跃用户数
Calculating active users within a 7 days period
问:
所以我有以下数据:
用户 ID | 创建上 |
---|---|
一个 | 01.01.2023 |
一个 | 02.01.2023 |
一个 | 03.01.2023 |
一个 | 05.01.2023 |
一个 | 06.01.2023 |
一个 | 07.01.2023 |
一个 | 08.01.2023 |
B | 01.01.2023 |
B | 02.01.2023 |
B | 03.01.2023 |
B | 04.01.2023 |
B | 05.01.2023 |
B | 06.01.2023 |
B | 07.01.2023 |
我需要计算连续 7 天登录的用户数。例如,由于我们在 4 日中断,因此不会计算用户 A,但用户 B 将被计算一次。它应该是任何 7 天的时间段。有人可以帮我写代码吗? 我正在使用 SQL Server。谢谢
我尝试了行号和滞后,但不知道从哪里获取它。
with x as (
select distinct
UserId,
CreatedOn,
LAG(CreatedOn) OVER (PARTITION BY UserId ORDER BY CreatedOn) AS PrevDate,
ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY CreatedOn) AS RowNumber
from table)
select
*,
DATEDIFF(day, PrevDate, CreatedOn) date_diff,
case when DATEDIFF(day, PrevDate, CreatedOn) = 1 then RowNumber else 1 end as new_row
from table
答:
首先,将表联接到其自身,其中联接条件是针对同一用户,并且日期在当前行的日期范围内的行,回溯到过去的七天:
SELECT *
FROM [table] t1
INNER JOIN [table] t2 on t2.UserID = t1.UserID
AND t2.CreatedOn <= t1.CreatedOn AND t2.CreatedOn > DATEADD(day, -7, t1.CreatedOn)
现在,我们想进一步减少它,以仅显示每个源用户/日期的第二个表中的不同日期(假设它实际上是一个日期时间列,或者您可能有重复的日期):
SELECT DISTINCT t1.UserID, t1.CreatedOn, CAST(t2.CreatedOn AS Date) As CreatedOn As CreatedDate
FROM [table] t1
INNER JOIN [table] t2 on t2.UserID = t1.UserID
AND t2.CreatedOn <= t1.CreatedOn AND t2.CreatedOn > DATEADD(day, -7, t1.CreatedOn)
然后我们可以按用户进行分组,并查找有 7 条记录的用户组。因为我们已经做了一个 ,所以我们还需要将前面的步骤放在子查询或 CTE 中。最后,我们需要添加另一个 ,以便不会为每个额外的合格组(或跨度超过 7 天的每个额外天数)重复一个用户:DISTINCT
DISTINCT
SELECT DISTINCT UserID
FROM (
SELECT DISTINCT t1.UserID, t1.CreatedOn, CAST(t2.CreatedOn AS Date) As CreatedDate
FROM [table] t1
INNER JOIN [table] t2 on t2.UserID = t1.UserID
AND t2.CreatedOn <= t1.CreatedOn AND t2.CreatedOn > DATEADD(day, -7, t1.CreatedOn)
) t
GROUP BY UserID, CreatedOn
HAVING COUNT(CreatedDate) = 7
在这里看到它的工作:
如果您检查该链接,请注意我是如何格式化日期文字的。不同的文化、语言和方言对日期的格式有自己的期望,SQL 语言也不例外。无论您自己的区域性如何期望使用日期,在使用自己的 SQL 方言与数据库通信时,您都应该使用它自己的格式。对于 SQL Server,该格式是未分隔的 .在这个级别上使用是错误的,即使你和你的用户最终希望看到它。yyyyMMdd
dd.MM.yyyy
这是使用窗口函数(如 和)来做到这一点的方法:LAG()
SUM()
您有一个间隙和孤岛问题,您可以使用日期差异之间的差值和运行总和来为每组连续的行提供唯一的 ID。row_number
with cte as (
select UserId,
CreatedOn,
ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY CreatedOn) as rn,
LAG(CreatedOn) OVER (PARTITION BY UserId ORDER BY CreatedOn) AS PrevDate
from mytable
),
cte2 as (
select *, COALESCE(DATEDIFF(day, PrevDate, CreatedOn), 1) as date_diff
from cte
),
cte3 as (
select *, rn - sum(date_diff) OVER (PARTITION BY UserId ORDER BY CreatedOn) as grp
from cte2
)
select UserId
from cte3
group by UserId, grp
having count(*) >= 7
下一个:历史表上的合并操作
评论