合并存储为开始时间和结束时间的重叠时间段

时间:2018-10-04 10:55:31

标签: sql sql-server datetime sequence gaps-and-islands

我的DB表有两列有趣的内容,第一列是给定物理区域内许多事件的开始(或开启)时间,第二列是结束(或关闭)时间。

要求是确定车辆在该区域内的唯一时间段。因此,第一个事件的开始到最后一个事件的结束是一个连续的时间段。生成的表不需要该时间段内的开或关事件数。

有数百万行,因此由于结果表的大小,联接可能会导致问题。我不反对,但是...

数据:

id          timeOn                    timeOff
761058840   2018-01-02 07:54:28.000   2018-01-02 08:33:34.000
761058840   2018-01-02 07:54:28.000   2018-01-02 08:36:30.000
761058840   2018-01-02 08:33:45.000   2018-01-02 08:35:30.000
761058840   2018-01-02 13:11:18.000   2018-01-02 13:14:04.000
761058840   2018-01-02 13:11:18.000   2018-01-02 13:39:40.000
761058840   2018-01-02 13:22:11.000   2018-01-02 13:40:25.000
761058840   2018-01-02 15:56:18.000   2018-01-02 15:59:34.000
761058840   2018-01-02 15:56:18.000   2018-01-02 16:36:25.000
761058840   2018-01-02 16:01:34.000   2018-01-02 16:05:34.000
761058840   2018-01-02 16:33:19.000   2018-01-02 16:38:26.000
761058840   2018-01-02 21:20:25.000   2018-01-02 21:24:25.000
761058840   2018-01-02 22:20:36.000   2018-01-03 05:20:37.000
761058840   2018-01-02 22:20:36.000   2018-01-03 05:20:37.000
761058840   2018-01-03 08:31:29.000   2018-01-03 09:01:10.000
761058840   2018-01-03 08:31:59.000   2018-01-03 09:01:07.000
761058840   2018-01-03 09:01:57.000   2018-01-03 09:06:27.000
761058840   2018-01-03 14:07:27.000   2018-01-03 14:17:32.000
761058840   2018-01-03 14:09:28.000   2018-01-03 14:45:00.000
761058840   2018-01-03 14:19:32.000   2018-01-03 14:48:22.000
761058840   2018-01-03 17:30:38.000   2018-01-03 18:06:35.000
761058840   2018-01-03 17:33:54.000   2018-01-03 18:09:48.000

考虑此数据中的行,我正在寻找的是:

761058840   2018-01-02 07:54:28.000   2018-01-02 08:36:30.000
761058840   2018-01-02 13:11:18.000   2018-01-02 13:40:25.000
761058840   2018-01-02 15:56:18.000   2018-01-02 16:38:26.000
761058840   2018-01-02 21:20:25.000   2018-01-02 21:24:25.000
761058840   2018-01-02 22:20:36.000   2018-01-03 05:20:37.000
761058840   2018-01-03 08:31:59.000   2018-01-03 09:01:07.000
761058840   2018-01-03 09:01:57.000   2018-01-03 09:06:27.000
761058840   2018-01-03 14:07:27.000   2018-01-03 14:48:22.000
761058840   2018-01-03 17:30:38.000   2018-01-03 18:09:48.000

其他解决方案适用于约会,一个小时内我有多个活动。其他解决方案将事件分类为时段(按小时将它们合并)。

似乎没有什么可以持续的时间了。

数据库是SQL Server,因此T-SQL或ANSI是理想的选择,但我已经准备好进行一些翻译了。

(为澄清起见,我正在尝试将timeOn到timeOff的重叠时间序列合并为每个连续序列的一行)

1 个答案:

答案 0 :(得分:3)

这是合并重叠间隔的经典问题。最简单的解决方案是按起点和组行对数据进行排序,每当发现最大值与最大值之间的间隔时,就开始新的组。终点位于上一行的起点和当前行的起点。

以下解决方案基于此想法(我使用ROWS BETWEEN ...而非LAG):

WITH t_with_change AS (
    SELECT id, timeOn, timeOff, CASE WHEN MAX(timeOff) OVER (PARTITION BY ID ORDER BY timeOn ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) >= timeOn THEN 0 ELSE 1 END AS chg
    FROM @t
), t_with_groups AS(
    SELECT id, timeOn, timeOff, SUM(chg) OVER (PARTITION BY ID ORDER BY timeOn) AS grp
    FROM t_with_change
)
SELECT id, grp, MIN(timeOn) AS timeOn, MAX(timeOff) AS timeOff
FROM t_with_groups
GROUP BY id, grp

DB Fiddle