【sql】使用开窗函数求连续数据的分析思路

【sql】使用开窗函数求连续数据的分析思路

现有一张nba球队年度冠军表,需要把连续夺冠的球队以及连续范围内的开始年份、结束年份查询出来。
需要用到开窗函数,这里使用oracle数据库(mysql8以上版本也可使用开窗函数)

create table NBA
(
team varchar2(200),
y number(4)
);
insert into NBA (team, y) values ('活塞', 1990);
insert into NBA (team, y) values ('公牛', 1991);
insert into NBA (team, y) values ('公牛', 1992);
insert into NBA (team, y) values ('公牛', 1993);
insert into NBA (team, y) values ('火箭', 1994);
insert into NBA (team, y) values ('火箭', 1995);
insert into NBA (team, y) values ('公牛', 1996);
insert into NBA (team, y) values ('公牛', 1997);
insert into NBA (team, y) values ('公牛', 1998);
insert into NBA (team, y) values ('马刺', 1999);
insert into NBA (team, y) values ('湖人', 2000);
insert into NBA (team, y) values ('湖人', 2001);
insert into NBA (team, y) values ('湖人', 2002);
insert into NBA (team, y) values ('马刺', 2003);
insert into NBA (team, y) values ('活塞', 2004);
insert into NBA (team, y) values ('马刺', 2005);
insert into NBA (team, y) values ('热火', 2006);
insert into NBA (team, y) values ('马刺', 2007);
insert into NBA (team, y) values ('凯尔特人', 2008);
insert into NBA (team, y) values ('湖人', 2009);
insert into NBA (team, y) values ('湖人', 2010);
  1. 使用ROW_NUMBER()按球队分组,年份排序;用年份减去序号,如果是连续夺冠,则得到的YR值相同。
SELECT n.*,Y-ROW_NUMBER() OVER(PARTITION BY TEAM ORDER BY Y) YR FROM NBA n

在这里插入图片描述
2. 统计YR的数量,用第1个年份加上数量再减1就可以得到结束年份。

SELECT a.*,Y+COUNT(*)OVER(PARTITION BY TEAM,YR)-1 y2,ROW_NUMBER ()OVER(PARTITION BY team ,yr ORDER BY yr)rn FROM (
SELECT n.*,Y-ROW_NUMBER() OVER(PARTITION BY TEAM ORDER BY Y) YR FROM NBA n)a

在这里插入图片描述
3. 最后只需要筛选RN为1并且起始年份与终止年份不相等的数据即可。

SELECT team,y 起始年份,y2 终止年份 from(
SELECT a.*,Y+COUNT(*)OVER(PARTITION BY TEAM,YR)-1 y2,ROW_NUMBER ()OVER(PARTITION BY team ,yr ORDER BY yr)rn FROM (
SELECT n.*,Y-ROW_NUMBER() OVER(PARTITION BY TEAM ORDER BY Y) YR FROM NBA n)a)WHERE rn=1 AND y <>y2 ;

在这里插入图片描述

要判断连续7天登录的情况,并且不使用开窗函数,可以通过自连接(self join)的方式实现。以下是详细的解决方案步骤和SQL示例: --- ### 解决方案 #### 假设场景 我们有一张记录用户每日登录情况的表 `login_log`,其字段包括: - `user_id`: 用户ID; - `login_date`: 登录日期。 我们需要找出哪些用户实现了连续7天登录。 --- #### 思路解析 1. **构造辅助列表示时间差** - 如果两个日期之间的差距为固定的数值,则它们可能是连续的时间段。 2. **通过自连接找到所有满足条件的组合** - 将当前用户的某一天与其他6天分别进行比较,检查是否构成连续7天的关系。 3. **去重并筛选最终结果** - 最终只需要保留符合条件的结果集即可。 --- #### SQL 实现 (MySQL) ```sql SELECT DISTINCT l1.user_id FROM login_log AS l1 JOIN login_log AS l2 ON l1.user_id = l2.user_id AND DATEDIFF(l2.login_date, l1.login_date) BETWEEN 0 AND 6 GROUP BY l1.user_id, l1.login_date HAVING COUNT(DISTINCT l2.login_date) >= 7; ``` --- ### 具体说明 1. **DATEDIFF() 函数的作用** - 计算两条记录之间的时间间隔(单位为天)。如果相差小于等于6天加上当天正好形成一组长度为7的数据序列。 2. **ON 条件设置** ```sql ON l1.user_id = l2.user_id AND DATEDIFF(l2.login_date, l1.login_date) BETWEEN 0 AND 6 ``` 表达了同一位用户的不同两天间的距离必须位于[0,6]范围内才能进一步验证是否存在完整的七日链。 3. **COUNT 和 HAVING 的功能** - 要对于任意选定的一个基准日子l1.login_date来说,在它之后六日内都存在相应有效访问记录的话才算是完成了持续性的任务目标;因此需要统计关联起来的所有不同日子数目不少于七个才行。(这里用DISTINCT去掉可能存在的重复计数问题) --- ### 注意事项 - 数据库引擎需支持 DATE 类型运算符如 MySQL/Presto 等;若换做其他数据库则应改写对应的日期计算逻辑部分。 - 此方法相比窗口函数较为笨拙低效,但在不允许使用后者的情况下仍是一种可行的选择。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值