选择没有重叠的行/动态 1 小时间隔

问题描述 投票:0回答:1
时间_开始 时间结束
'2024-01-01 12:30' '2024-01-01 13:30'
'2024-01-01 12:40' '2024-01-01 13:40'
'2024-01-01 12:45' '2024-01-01 13:45'
'2024-01-01 13:36' '2024-01-01 14:36'
'2024-01-01 13:50' '2024-01-01 14:50'
'2024-01-01 14:30' '2024-01-01 15:30'
'2024-01-01 15:35' '2024-01-01 16:35'
'2024-01-01 16:30' '2024-01-01 17:30'
'2024-01-01 17:30' '2024-01-01 18:30'

每个间隔都是一个事件周期。我需要显示第一个事件,然后第二个事件应该是下一个事件,其间隔不与第一个事件的间隔重叠。那么第三个事件应该是下一个不与第二个事件重叠的事件,依此类推。

预期输出:

时间_开始 时间结束
'2024-01-01 12:30' '2024-01-01 13:30'
'2024-01-01 13:36' '2024-01-01 14:36'
'2024-01-01 15:35' '2024-01-01 16:35'
'2024-01-01 17:30' '2024-01-01 18:30'

我尝试过类似的方法,但它没有给我预期的输出:

WITH Intervalle AS (
    SELECT
        start_time,
        end_time,
        LAG(end_time) OVER (ORDER BY start_time) AS previous_end_time
    FROM
        deine_tabelle
)
SELECT
    start_time,
    end_time
FROM
    Intervalle
WHERE
    previous_end_time IS NULL
    OR start_time >= previous_end_time + INTERVAL 1 HOUR
ORDER BY
    start_time;
sql sql-server intervals gaps-and-islands
1个回答
0
投票

我将根据您发布的查询中的

INTERVAL 1 HOUR
表达式来假设 MySQL。

这是“间隙与岛屿”问题的变体。但是,与典型的间隙和岛屿情况不同,我不认为您可以使用 LAG()' and 'LEAD() 函数来识别“间隙”,因为每行的状态可能取决于

every
前一行的结果。还有其他方法... 您可以使用递归 CTE 选择第一行,然后重复选择下一个符合条件的行 - 两者都使用子查询,通过

ORDER BY

LIMIT 1
的组合来选择下一个“最佳”行。
WITH RECURSIVE TaggedIntervals AS (
    SELECT
        I2.*,
        1 AS IsGap,
        1 AS Island,
        I2.time_start AS ref_time
    FROM (
        SELECT I.*
        FROM Intervalle I
        ORDER BY I.time_start
        LIMIT 1
    ) I2

    UNION ALL

    SELECT
        I2.*,
        T.Island + I2.IsGap AS Island,
        CASE WHEN I2.IsGap = 1 THEN I2.time_start ELSE T.ref_time END AS ref_time
    FROM TaggedIntervals T
    , LATERAL (
        SELECT
            I.*,
            CASE WHEN I.time_start >= T.ref_time + INTERVAL 1 HOUR
                 THEN 1 ELSE 0 END AS IsGap
        FROM Intervalle I
        WHERE I.time_start > T.time_start
        ORDER BY I.time_start
        LIMIT 1
    ) I2
)
SELECT *
FROM TaggedIntervals

结果:

时间_开始2024-01-01 12:30:002024-01-01 13:36:002024-01-01 15:35:002024-01-01 17:30:00
时间结束
2024-01-01 13:30:00
2024-01-01 14:36:00
2024-01-01 16:35:00
2024-01-01 18:30:00
如果您希望使用
间隙和岛

方法,您可以按顺序处理所有行,同时跟踪每个“岛”的time_start。每个

time_start
与当前岛屿的比较可用于识别“差距”。间隙标志的运行总和可用于对岛屿进行编号。
WITH RECURSIVE TaggedIntervals AS (
    SELECT
        I2.*,
        1 AS IsGap,
        1 AS Island,
        I2.time_start AS ref_time
    FROM (
        SELECT I.*
        FROM Intervalle I
        ORDER BY I.time_start
        LIMIT 1
    ) I2

    UNION ALL

    SELECT
        I2.*,
        T.Island + I2.IsGap AS Island,
        CASE WHEN I2.IsGap = 1 THEN I2.time_start ELSE T.ref_time END AS ref_time
    FROM TaggedIntervals T
    , LATERAL (
        SELECT
            I.*,
            CASE WHEN I.time_start >= T.ref_time + INTERVAL 1 HOUR
                 THEN 1 ELSE 0 END AS IsGap
        FROM Intervalle I
        WHERE I.time_start > T.time_start
        ORDER BY I.time_start
        LIMIT 1
    ) I2
)
SELECT *
FROM TaggedIntervals

这假设没有重复的时间。如果您需要处理此类情况,您可能需要首先使用 
ROW_NUMBER()

对行进行编号,然后使用该行号对行进行排序。

结果:

时间_开始2024-01-01 12:30:002024-01-01 12:40:002024-01-01 12:45:002024-01-01 13:36:002024-01-01 13:50:002024-01-01 14:30:002024-01-01 15:35:002024-01-01 16:30:002024-01-01 17:30:00
时间结束 是差距 岛屿 参考时间
2024-01-01 13:30:00 1 1 2024-01-01 12:30:00
2024-01-01 13:40:00 0 1 2024-01-01 12:30:00
2024-01-01 13:45:00 0 1 2024-01-01 12:30:00
2024-01-01 14:36:00 1 2 2024-01-01 13:36:00
2024-01-01 14:50:00 0 2 2024-01-01 13:36:00
2024-01-01 15:30:00 0 2 2024-01-01 13:36:00
2024-01-01 16:35:00 1 3 2024-01-01 15:35:00
2024-01-01 17:30:00 0 3 2024-01-01 15:35:00
2024-01-01 18:30:00 1 4 2024-01-01 17:30:00
此时,您可以添加逻辑进行分组
Island

并应用实现所需结果所需的任何聚合函数。

请参阅 

this db<>fiddle

进行演示。

© www.soinside.com 2019 - 2024. All rights reserved.