SQL 查询连续月份登录

SQL Query Sequential Month Logins

我有以下SQLtable

username Month
292 10
123 12
123 1
123 2
123 4
345 6
345 7

我想查询它,以获取每个用户名在连续月份计数中的登录记录。这意味着我正在寻找的最终结果看起来像这样:

username Streak
292 1
123 3
345 2

如何实现?注意到第 12 个月 --> 第 1 个月的问题;

感谢您的帮助;

一种方法是使用递归 CTE,例如

WITH RECURSIVE cte (username, month, cnt) AS
(
 SELECT username, month, 1
 FROM test
 UNION ALL
 SELECT test.username, test.month, cte.cnt+1
 FROM cte INNER JOIN test
  ON cte.username = test.username AND CASE WHEN cte.month = 12 THEN 1 ELSE cte.month + 1 END = test.month
)
SELECT username, MAX(cnt)
FROM cte
GROUP BY username
ORDER BY username

想法是 CTE(在我的示例中命名为 cte)在用户相同且月份是下一个的条件下递归地连接回 table。因此对于用户 345,您有:

Username Month Cnt
345 6 1
345 7 1
345 7 2

cnt=1 的行来自原始 table(额外的 cnt 列硬编码为 1),cnt=2 的行来自查询的递归部分(它找到了匹配项并使用 cnt+1 作为其 cnt)。然后查询为每个用户选择最大值。

连接使用 CASE 语句来处理 12 后跟 1。

可以看到working with your sample data in this fiddle.

@EdmCoff 分享的那款还是挺优雅的。

另一个没有递归并且只使用条件逻辑的 -

with data_cte as
(
select username, month_1,
case when (count(month_1) over (partition by username) = 1) then 1
when (lead(month_1) over (partition by username order by username) - month_1) = 1  OR (month_1 - lag(month_1) over (partition by username order by username)) = 1 then 1
when (month_1 = 12 and min (month_1) over (partition by username) =1) then 1
end cnt
from login_tab 
  )
  select username, count(cnt) from data_cte group by username

DB Fiddle here.

这会给你想要的结果:

select username, count(*)
from (
    select 
    username
    , month_1
    , coalesce(nullif(lead(month_1) 
                      over (partition by username 
                            order by coalesce(nullif(month_1,12),0))
                      - coalesce(nullif(month_1,12),0),-1),1) as MonthsTillNext
from login_tab 
  ) Step1
where MonthsTillNext=1
group by username

通过计算与下一行的差异,其中下一行定义为升序排列的下一个month_no,将12视为0(参考我评论中提到的歧义)。然后它只留下连续月份的行,并对它们进行计数。

但请注意,除了 month:12 周围的异常情况之外,还有另一种情况未被考虑:如果用户的月份是 1、2、3 和 6、7、8,这将算作 Streak:6;是你想要的吗?