对于给定的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
展平结果:
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
这是仅SQL的解决方案。我使用DATETIME作为列。在我看来,将时间分开存储是错误的,因为当时间超过午夜时,您将遇到问题。您也可以根据需要对此进行调整。该解决方案还假定开始时间和结束时间不为空。同样,如果不是这种情况,您可以根据需要进行调整。
该解决方案的总体要旨是获取不与任何其他跨度重叠的所有开始时间,获取不与任何跨度重叠的所有结束时间,然后将两者进行匹配。
结果与您的预期结果相符,但在一种情况下,用手检查似乎您的预期输出有误。在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