VVS*_*VVS 15 sql sql-server algorithm datetime sql-server-2005
我有很多关于给定ID的开始和停止时间的数据,我需要将所有相交和相邻的时间平移为一个组合的时间跨度.下面发布的样本数据都是相同的ID,所以我没有列出它.
为了使事情更清楚,请查看03.06.2009的示例数据:
以下时间跨度是重叠或连续的,需要合并为一个时间跨度
由此产生的时间跨度为05:54:48至10:00:13.由于在10:00:13和10:12:50之间存在差距,我们还有以下时间间隔:
这导致从10:12:50到14:02:31的一个合并时间跨度,因为它们是重叠或相邻的.
您将在下面找到我需要的示例数据和展平数据.持续时间列只是提供信息.
任何解决方案 - 无论是SQL还是非 - 都表示赞赏.
编辑:由于有很多不同的和有趣的解决方案,我正在通过添加约束来查看"最佳"(如果有)解决方案泡沫,从而完善我的原始问题:
在这些限制范围内,最佳解决方案是什么?我担心大多数解决方案都会非常慢,因为他们加入了日期和时间的组合,这在我的案例中不是索引字段.
你会在客户端或服务器端进行所有合并吗?您是否首先创建一个优化的临时表并使用该表提出的解决方案之一?到目前为止我没有时间测试解决方案,但我会告诉您最适合我的方法.
样本数据:
Date | Start | Stop
-----------+----------+---------
02.06.2009 | 05:55:28 | 09:58:27
02.06.2009 | 10:15:19 | 13:58:24
02.06.2009 | 13:58:24 | 13:58:43
03.06.2009 | 05:54:48 | 10:00:13
03.06.2009 | 09:26:45 | 09:59:40
03.06.2009 | 10:12:50 | 10:27:25
03.06.2009 | 10:13:12 | 11:14:56
03.06.2009 | 10:27:25 | 10:27:31
03.06.2009 | 10:27:39 | 13:53:38
03.06.2009 | 11:14:56 | 11:15:03
03.06.2009 | 11:15:30 | 14:02:14
03.06.2009 | 13:53:38 | 13:53:43
03.06.2009 | 14:02:14 | 14:02:31
04.06.2009 | 05:48:27 | 09:58:59
04.06.2009 | 06:00:00 | 09:59:07
04.06.2009 | 10:15:52 | 13:54:52
04.06.2009 | 10:16:01 | 13:24:20
04.06.2009 | 13:24:20 | 13:24:24
04.06.2009 | 13:24:32 | 14:00:39
04.06.2009 | 13:54:52 | 13:54:58
04.06.2009 | 14:00:39 | 14:00:49
05.06.2009 | 05:53:58 | 09:59:12
05.06.2009 | 10:16:05 | 13:59:08
05.06.2009 | 13:59:08 | 13:59:16
06.06.2009 | 06:04:00 | 10:00:00
06.06.2009 | 10:16:54 | 10:18:40
06.06.2009 | 10:18:40 | 10:18:45
06.06.2009 | 10:23:00 | 13:57:00
06.06.2009 | 10:23:48 | 13:57:54
06.06.2009 | 13:57:21 | 13:57:38
06.06.2009 | 13:57:54 | 13:57:58
07.06.2009 | 21:59:30 | 01:58:49
07.06.2009 | 22:12:16 | 01:58:39
07.06.2009 | 22:12:25 | 01:58:28
08.06.2009 | 02:10:33 | 05:56:11
08.06.2009 | 02:10:43 | 05:56:23
08.06.2009 | 02:10:49 | 05:55:59
08.06.2009 | 05:55:59 | 05:56:01
08.06.2009 | 05:56:11 | 05:56:14
08.06.2009 | 05:56:23 | 05:56:27
Run Code Online (Sandbox Code Playgroud)
扁平化结果:
Date | Start | Stop | Duration
-----------+----------+----------+---------
02.06.2009 | 05:55:28 | 09:58:27 | 04:02:59
02.06.2009 | 10:15:19 | 13:58:43 | 03:43:24
03.06.2009 | 05:54:48 | 10:00:13 | 04:05:25
03.06.2009 | 10:12:50 | 14:02:31 | 03:49:41
04.06.2009 | 05:48:27 | 09:59:07 | 04:10:40
04.06.2009 | 10:15:52 | 14:00:49 | 03:44:58
05.06.2009 | 05:53:58 | 09:59:12 | 04:05:14
05.06.2009 | 10:16:05 | 13:59:16 | 03:43:11
06.06.2009 | 06:04:00 | 10:00:00 | 03:56:00
06.06.2009 | 10:16:54 | 10:18:45 | 00:01:51
06.06.2009 | 10:23:00 | 13:57:58 | 03:34:58
07.06.2009 | 21:59:30 | 01:58:49 | 03:59:19
08.06.2009 | 02:10:33 | 05:56:27 | 03:45:54
Run Code Online (Sandbox Code Playgroud)
这是一个仅限SQL的解决方案.我使用DATETIME作为列.在我看来,将时间分开存储是个错误,因为当时间超过午夜时你会遇到问题.如果需要,您可以调整此值来处理这种情况.该解决方案还假定开始和结束时间不是NULL.同样,如果不是这样,您可以根据需要进行调整.
解决方案的一般要点是获得不与任何其他跨度重叠的所有开始时间,获得不与任何跨度重叠的所有结束时间,然后将两者匹配在一起.
结果与您的预期结果相符,但在一种情况下,手动检查看起来您的预期输出有误.在6日应该有一个跨度结束于2009-06-06 10:18:45.000.
SELECT
ST.start_time,
ET.end_time
FROM
(
SELECT
T1.start_time
FROM
dbo.Test_Time_Spans T1
LEFT OUTER JOIN dbo.Test_Time_Spans T2 ON
T2.start_time < T1.start_time AND
T2.end_time >= T1.start_time
WHERE
T2.start_time IS NULL
) AS ST
INNER JOIN
(
SELECT
T3.end_time
FROM
dbo.Test_Time_Spans T3
LEFT OUTER JOIN dbo.Test_Time_Spans T4 ON
T4.end_time > T3.end_time AND
T4.start_time <= T3.end_time
WHERE
T4.start_time IS NULL
) AS ET ON
ET.end_time > ST.start_time
LEFT OUTER JOIN
(
SELECT
T5.end_time
FROM
dbo.Test_Time_Spans T5
LEFT OUTER JOIN dbo.Test_Time_Spans T6 ON
T6.end_time > T5.end_time AND
T6.start_time <= T5.end_time
WHERE
T6.start_time IS NULL
) AS ET2 ON
ET2.end_time > ST.start_time AND
ET2.end_time < ET.end_time
WHERE
ET2.end_time IS NULL
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3021 次 |
最近记录: |