[英]SQL row_number with a condition
我想用 case 条件配置 row_number。 查看“time_diffs”列并检查 - 如果有 1 的 go 一个一个,那么它就是一组。 如果有 0,则每个 0 本身就是一组。 在 1 和 0 之间的每次迭代之后,行结果将在 +1 上增长。
select session_id,
player_id,
country,
start_time,
end_time,
case when timestampdiff(minute,
lag(end_time, 1) over(partition by player_id order by end_time)
, start_time) < 5 then 1
when timestampdiff(minute, end_time
, lead(start_time, 1) over(partition by player_id order by start_time)) < 5 then 1
else 0
end as time_diffs
/* , here is some new code with an expected result */
from game_sessions
where 1=1
and player_id = 1
order by player_id, start_time
当前查询结果:
session_id | player_id | 国家 | 开始时间 | 时间结束 | 时差 |
---|---|---|---|---|---|
1个 | 1个 | 英国 | 01.01.2021 00:01 | 01.01.2021 00:10 | 1个 |
2个 | 1个 | 英国 | 01.01.2021 00:12 | 01.01.2021 01:24 | 1个 |
13 | 1个 | 英国 | 01.01.2021 01:27 | 01.01.2021 01:50 | 1个 |
3个 | 1个 | 英国 | 01.01.2021 10:01 | 01.01.2021 15:10 | 0 |
16 | 1个 | 英国 | 01.01.2021 17:10 | 01.01.2021 17:20 | 1个 |
17 | 1个 | 英国 | 01.01.2021 17:22 | 01.01.2021 17:55 | 1个 |
54 | 1个 | 英国 | 01.01.2021 18:15 | 01.01.2021 18:35 | 0 |
32 | 1个 | 英国 | 01.01.2021 18:55 | 01.01.2021 19:35 | 0 |
我希望在当前查询中添加新列时看到的内容:
session_id | player_id | 国家 | 开始时间 | 时间结束 | 时差 | 预期结果 |
---|---|---|---|---|---|---|
1个 | 1个 | 英国 | 01.01.2021 00:01 | 01.01.2021 00:10 | 1个 | 1个 |
2个 | 1个 | 英国 | 01.01.2021 00:12 | 01.01.2021 01:24 | 1个 | 1个 |
13 | 1个 | 英国 | 01.01.2021 01:27 | 01.01.2021 01:50 | 1个 | 1个 |
3个 | 1个 | 英国 | 01.01.2021 10:01 | 01.01.2021 15:10 | 0 | 2个 |
16 | 1个 | 英国 | 01.01.2021 17:10 | 01.01.2021 17:20 | 1个 | 3个 |
17 | 1个 | 英国 | 01.01.2021 17:22 | 01.01.2021 17:55 | 1个 | 3个 |
54 | 1个 | 英国 | 01.01.2021 18:15 | 01.01.2021 18:35 | 0 | 4个 |
32 | 1个 | 英国 | 01.01.2021 18:55 | 01.01.2021 19:35 | 0 | 5个 |
这是一种[差距和孤岛问题],需要一些窗口函数(和子查询)才能得到你想要的结果,第一步是计算出你的差距和岛屿,你可以使用两个 row_numbers,一个有一个额外的分区:
SELECT *,
ROW_NUMBER() OVER (PARTITION BY player_id ORDER BY start_time)
- ROW_NUMBER() OVER (PARTITION BY player_id, time_diffs ORDER BY start_time) AS GroupingSet
FROM game_sessions;
注意:对于这个查询和所有其他查询,我已经采取了简化整个查询的步骤,将字段time_diffs
包含在数据集中以缩短实际查询
这给出:
session_id | player_id | 国家 | 开始时间 | 时间结束 | 时差 | 分组集 |
---|---|---|---|---|---|---|
1个 | 1个 | 英国 | 2021-01-01 00:01:00 | 2021-01-01 00:10:00 | 1个 | 0 |
2个 | 1个 | 英国 | 2021-01-01 00:12:00 | 2021-01-01 01:24:00 | 1个 | 0 |
13 | 1个 | 英国 | 2021-01-01 01:27:00 | 2021-01-01 01:50:00 | 1个 | 0 |
3个 | 1个 | 英国 | 2021-01-01 10:01:00 | 2021-01-01 15:10:00 | 0 | 3个 |
16 | 1个 | 英国 | 2021-01-01 17:10:00 | 2021-01-01 17:20:00 | 1个 | 1个 |
17 | 1个 | 英国 | 2021-01-01 17:22:00 | 2021-01-01 17:55:00 | 1个 | 1个 |
54 | 1个 | 英国 | 2021-01-01 18:15:00 | 2021-01-01 18:35:00 | 0 | 5个 |
32 | 1个 | 英国 | 2021-01-01 18:55:00 | 2021-01-01 19:35:00 | 0 | 5个 |
您在这里可以看到,每次您的 time_diff 更改时,“GroupingSet”列都会更改,这是识别您的岛屿(相同值的连续组)的基础。
对于您的 output 然后您需要几个额外的窗口函数,首先您需要获得每组的最小开始时间,因为您想要将每一行视为time_diffs = 0
的唯一组,您需要以下表达式:
IF(time_diffs=1,MIN(start_time) OVER (PARTITION BY player_id, p.GroupingSet),start_time)
添加此列然后给出:
session_id | player_id | 国家 | 开始时间 | 时间结束 | 时差 | 分组集 | 组开始 |
---|---|---|---|---|---|---|---|
1个 | 1个 | 英国 | 2021-01-01 00:01:00 | 2021-01-01 00:10:00 | 1个 | 0 | 2021-01-01 00:01:00 |
2个 | 1个 | 英国 | 2021-01-01 00:12:00 | 2021-01-01 01:24:00 | 1个 | 0 | 2021-01-01 00:01:00 |
13 | 1个 | 英国 | 2021-01-01 01:27:00 | 2021-01-01 01:50:00 | 1个 | 0 | 2021-01-01 00:01:00 |
3个 | 1个 | 英国 | 2021-01-01 10:01:00 | 2021-01-01 15:10:00 | 0 | 3个 | 2021-01-01 10:01:00 |
16 | 1个 | 英国 | 2021-01-01 17:10:00 | 2021-01-01 17:20:00 | 1个 | 1个 | 2021-01-01 17:10:00 |
17 | 1个 | 英国 | 2021-01-01 17:22:00 | 2021-01-01 17:55:00 | 1个 | 1个 | 2021-01-01 17:10:00 |
54 | 1个 | 英国 | 2021-01-01 18:15:00 | 2021-01-01 18:35:00 | 0 | 5个 | 2021-01-01 18:15:00 |
32 | 1个 | 英国 | 2021-01-01 18:55:00 | 2021-01-01 19:35:00 | 0 | 5个 | 2021-01-01 18:55:00 |
最后,您可以使用此MinStart
列作为DENSE_RANK()
的基础,给出最终查询
SELECT p.session_id,
p.player_id,
p.country,
p.start_time,
p.end_time,
p.time_diffs,
DENSE_RANK() OVER(PARTITION BY player_id ORDER BY p.GroupStart) AS ExpectedOutput
FROM
(
SELECT *, IF(time_diffs = 0,start_time,MIN(start_time) OVER (PARTITION BY player_id, p.GroupingSet)) AS GroupStart
FROM
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY player_id ORDER BY start_time)
- ROW_NUMBER() OVER (PARTITION BY player_id, time_diffs ORDER BY start_time) AS GroupingSet
FROM game_sessions
) AS p
) AS p
ORDER BY
player_id, start_time;
一个可能更简单的替代方法是识别您不想增加计数的行,然后返回 0,否则返回 1,即
IF(time_diffs=1 AND LAG(time_diffs,1,0) OVER(PARTITION BY player_id ORDER BY start_time)=1,0,1)
然后对这一列求和:
SELECT p.session_id,
p.player_id,
p.country,
p.start_time,
p.end_time,
p.time_diffs,
SUM(TDChanges) OVER(PARTITION BY player_id ORDER BY p.time_start) AS ExpectedOutput
FROM
(
SELECT *,
IIF(time_diffs=1 AND LAG(time_diffs,1,0) OVER(PARTITION BY player_id ORDER BY time_start)=1,0,1) AS TDChanges
FROM game_sessions
) AS p
ORDER BY
player_id, start_time;
这两个查询都给出了您预期的 output - db<>fidle 上的示例
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.