如何查询连续3天及以上距离为0的人员及对应天数?
问题背景
现有数据表结构及数据如下:
| Date | Person | Distance |
|---|---|---|
| 2022/01/01 | John | 15 |
| 2022/01/02 | John | 0 |
| 2022/01/03 | John | 0 |
| 2022/01/04 | John | 0 |
| 2022/01/05 | John | 19 |
| 2022/01/01 | Pete | 25 |
| 2022/01/02 | Pete | 12 |
| 2022/01/03 | Pete | 0 |
| 2022/01/04 | Pete | 0 |
| 2022/01/05 | Pete | 1 |
需求
找出所有连续3天及以上Distance为0的人员,并统计其最长连续天数。示例中预期结果如下:
| Person | Consecutive Days with Zero |
|---|---|
| John | 3 |
用户尝试的SQL(存在问题)
Select Person, count(*), (row_number() over (partition by Person, Date order by Person, Date)) from mytable
问题分析与正确解法
你写的SQL存在几个核心问题:
- 未筛选
Distance = 0的记录,会把所有数据纳入计算,偏离需求 - 分区条件用
Person, Date完全不合理——每个日期唯一,分区后每组仅一条数据,row_number()无法实现连续天数分组 - 缺乏连续日期的判断逻辑,单纯
count(*)无法统计连续天数
要解决连续天数统计问题,核心思路是给每个连续的0距离日期组打标记,具体实现步骤如下:
- 先筛选出所有
Distance = 0的记录 - 对每个人员按日期排序,通过日期与行号的差值识别连续日期组
- 按人员和连续组分组统计天数,最后筛选出天数≥3的记录
以下是适配多数SQL数据库(MySQL、PostgreSQL、SQL Server)的代码:
WITH zero_days AS ( SELECT Person, Date, -- 给每个人员的0距离日期按顺序编号 ROW_NUMBER() OVER (PARTITION BY Person ORDER BY Date) AS rn FROM mytable WHERE Distance = 0 ), consecutive_groups AS ( SELECT Person, -- 通过日期减行号的固定偏移量,标记同一连续组 DATE_SUB(Date, INTERVAL rn DAY) AS group_id -- MySQL写法 -- PostgreSQL 替换为:(Date - INTERVAL '1 day' * rn) AS group_id -- SQL Server 替换为:DATEADD(day, -rn, Date) AS group_id FROM zero_days ), group_counts AS ( SELECT Person, COUNT(*) AS consecutive_days FROM consecutive_groups GROUP BY Person, group_id HAVING COUNT(*) >= 3 ) SELECT Person, MAX(consecutive_days) AS `Consecutive Days with Zero` FROM group_counts GROUP BY Person;
代码逻辑说明:
zero_days:筛选出所有距离为0的记录,给每个人员的日期按顺序编号consecutive_groups:利用日期与行号的差值,将连续日期归为同一个group_id(连续日期的日期差与行号差相等,差值结果一致)group_counts:按人员和分组统计连续天数,筛选出天数≥3的组- 最终取每个人员的最长连续天数,得到符合需求的结果
内容的提问来源于stack exchange,提问作者Cameron Castillo
相关产品推荐
相关产品推荐

