时间_开始 | 时间结束 |
---|---|
'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;
我将根据您发布的查询中的
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 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 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