sql判断是否连续并生成连续分组id

目录

一、需求

二、测试案例

1.测试数据

2.实现

3.结果 


一、需求

想实现根据时间升序排序取出同班级下一个进入班级的时间,然后判断同一班级上一个人和下一个人是否连续,并生成符合分组条件的连续分组id。

二、测试案例

1.测试数据

create table test_detail(
id   bigint comment '主键',
num  string comment '班级号码',
name string comment '名字',
start_timestamp bigint comment '进入班级时间'
)comment '测试数据明细'
row format delimited fields terminated by '\t'
stored as textfile;

insert into table test_detail values(1,'01','桑稚',1666826633);
insert into table test_detail values(2,'01','桑稚',1666826857);
insert into table test_detail values(3,'01','桑稚',1666826883);
insert into table test_detail values(4,'01','温以凡',1666914770);
insert into table test_detail values(5,'01','温以凡',1666915255);
insert into table test_detail values(6,'01','温以凡',1666915791);
insert into table test_detail values(7,'01','桑稚',1666915843);
insert into table test_detail values(8,'01','桑稚',1666916328);
insert into table test_detail values(9,'01','桑稚',1666916493);
insert into table test_detail values(10,'02','段嘉许',1667002192);
insert into table test_detail values(11,'02','桑延',1666139582);
insert into table test_detail values(12,'02','段嘉许',1666140046);
insert into table test_detail values(13,'02','段嘉许',1666140076);

2.实现

select 
    id              --主键
   ,num             --班级号码
   ,name            --名字
   ,start_timestamp --进入班级时间
   ,lead(start_timestamp,1,2000000000) over(partition by num order by start_timestamp asc ) as end_timestamp 
   --同一班级下一个进入班级时间(最后一个人没有下一位,默认为2000000000)
   ,lag(name)  over(partition by num order by start_timestamp asc ) as last_name 
   --同一班级上一位进入班级的人
   ,lead(name) over(partition by num order by start_timestamp asc ) as next_name 
   --同一班级下一位进入班级的人
   ,row_number() over (partition by num order by start_timestamp asc) 
         -rank() over (partition by num,name order by start_timestamp)  as group_id 
   --连续内容的分组id
   ,case when name=lag(name) over(partition by num order by start_timestamp asc ) or
              name=lead(name) over(partition by num order by start_timestamp asc )
         then 1 else 0 
    end as is_continue 
   --判断同一班级进入班级的人是否连续,1为连续,0为不连续
from test_detail
;

3.结果 

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=cxkyozjkzjzv

<think>好的,用户现在问的是如何在SQL中求连续十天登录的问题。这个问题其实挺常见的,特别是在处理用户行为数据的时候。用户可能需要找出那些连续十天都登录的用户,可能是为了做活动奖励或者分析用户活跃度。 首先,我需要回忆一下之前用户问过的关于窗口函数的问题,比如ROW_NUMBER、RANK和DENSE_RANK的区别。现在这个问题可能也会用到窗口函数,尤其是ROW_NUMBER,因为连续登录的问题通常涉及到日期的连续判断。 用户的需求是找到连续登录十天的用户,可能的场景包括用户留存分析、活跃用户筛选或者奖励机制。但用户可能没有说明具体的数据结构,比如用户登录记录表的结构,比如是否有用户ID和登录日期字段,是否需要去重,因为同一个用户可能在同一天有多次登录记录。 接下来,我需要考虑解决方案。常见的解决连续问题的办法是使用窗口函数,通过将登录日期与行号结合,找到连续的日期。例如,给每个用户的登录日期排序,然后用登录日期减去行号的天数,如果连续的话,这个差值会相同。这样分组后统计每组的日期数量,就能找到连续的天数。 不过,这里需要注意去重,因为同一个用户可能在同一天登录多次,所以需要先对日期进行去重处理,使用DISTINCT或者GROUP BY来确保每个用户每天只有一条记录。 然后,构建步骤:首先获取每个用户每天的登录记录,按用户分组按日期排序,然后使用ROW_NUMBER()生成序号,接着用登录日期减去序号的天数得到一个分组标识。如果日期是连续的,那么这个分组标识会是相同的。最后,统计每个分组内的天数是否大于等于10天。 可能还需要考虑日期的格式,比如是否是日期类型,是否需要转换,以及性能问题,如果数据量大的话,这样的查询可能会比较慢,需要适当的索引优化。 用户可能还会关心具体的SQL写法,所以需要给出示例代码,解释每一步的作用。同时,可能需要提醒用户关于去重和日期处理的问题,比如如果表中存在时间戳,可能需要转换为日期格式。 另外,还要考虑是否有用户可能断断续续登录,但中间有中断,如何排除这些情况。比如,连续十天中间不能有一天缺失,所以分组后的日期数量必须至少有一次达到10天。 最后,总结一下步骤,确保用户能够理解应用到实际的数据表中,同时提醒他们根据实际表结构调整字段名和条件。</think>在SQL中计算**连续N天登录**的问题(例如连续10天),核心思路是通过日期与排序的差值标识连续区间,以下是分步解决方案: --- ### 一、数据准备 假设有用户登录表 `login_records`,包含字段: - `user_id`(用户ID) - `login_date`(登录日期,需去重处理) **示例数据**: | user_id | login_date | |---------|------------| | 1 | 2023-01-01 | | 1 | 2023-01-02 | | 1 | 2023-01-03 | | ... | ... | --- ### 二、解决步骤 #### 1. **去重处理** 若存在同一天多次登录的情况,先对日期去重: ```sql WITH distinct_dates AS ( SELECT user_id, DATE(login_date) AS login_date -- 确保格式为日期类型 FROM login_records GROUP BY user_id, DATE(login_date) -- 去重 ) ``` #### 2. **生成连续标识** 使用窗口函数 `ROW_NUMBER()` 为每个用户的登录日期排序,再通过**日期 - 序号天数**生成分组标识: ```sql , date_groups AS ( SELECT user_id, login_date, -- 按用户分组,按日期排序 login_date - INTERVAL ROW_NUMBER() OVER ( PARTITION BY user_id ORDER BY login_date ) DAY AS group_flag -- 关键:连续日期差值相同 FROM distinct_dates ) ``` #### 3. **统计连续天数** 按用户和分组标识聚合,筛选连续天数≥10的记录: ```sql SELECT user_id, MIN(login_date) AS start_date, -- 连续区间起始日期 MAX(login_date) AS end_date, -- 连续区间结束日期 COUNT(*) AS consecutive_days -- 连续天数 FROM date_groups GROUP BY user_id, group_flag HAVING COUNT(*) >= 10; -- 筛选连续10天及以上 ``` --- ### 三、原理解析 1. **ROW_NUMBER()** 为每个用户的日期生成连续序号(如1,2,3...) 2. **login_date - 序号天数**: - 若日期连续,例如 `2023-01-01`(序号1)、`2023-01-02`(序号2),则差值为 `2023-01-01 - 1 day = 2022-12-31`,`2023-01-02 - 2 days = 2022-12-31`,两者`group_flag`相同 - 若日期中断,差值会变化,从而区分不同连续区间 --- ### 四、最终完整SQL ```sql WITH distinct_dates AS ( SELECT user_id, DATE(login_date) AS login_date FROM login_records GROUP BY user_id, DATE(login_date) ), date_groups AS ( SELECT user_id, login_date, login_date - INTERVAL ROW_NUMBER() OVER ( PARTITION BY user_id ORDER BY login_date ) DAY AS group_flag FROM distinct_dates ) SELECT user_id, MIN(login_date) AS start_date, MAX(login_date) AS end_date, COUNT(*) AS consecutive_days FROM date_groups GROUP BY user_id, group_flag HAVING COUNT(*) >= 10; ``` --- ### 五、注意事项 1. **日期格式**:确保`login_date`为日期类型(非时间戳) 2. **跨月/跨年**:此方法自动处理跨月跨年的日期计算 3. **性能优化**:对`user_id`和`login_date`建立联合索引
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值