繁体   English   中英

SQL row_number 有条件

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM