【发布时间】:2011-05-16 13:51:33
【问题描述】:
目前我有一个这样建立的表
DeviceID Timestamp Value
----------------------------------------
Device1 1.1.2011 10:00:00 3
Device1 1.1.2011 10:00:01 4
Device1 1.1.2011 10:00:02 4
Device1 1.1.2011 10:00:04 3
Device1 1.1.2011 10:00:05 4
Device1 1.1.2011 14:23:14 8
Device1 1.1.2011 14:23:15 7
Device1 1.1.2011 14:23:17 4
Device1 1.1.2011 14:23:18 2
如您所见,某些值来自具有给定时间戳的设备(列类型为日期时间)。
问题是设备可以在任何时候启动和停止,并且数据中没有直接信息表明发生了启动或停止。但是从给定的时间戳列表中很容易判断何时开始和停止发生,因为只要两行的时间戳在 5 秒内,它们就属于同一个度量值。
现在我想从这些数据中得到一个这样的列表:
DeviceID Started Ended
Device1 1.1.2011 10:00:00 1.1.2011 10:00:05
Device1 1.1.2011 14:23:14 1.1.2011 14:23:18
那么有什么想法可以快速做到这一点吗?我所能想到的就是使用某种游标并手动比较每个日期时间对。但我认为这会变得非常慢,因为我们必须检查每一行中的每个值。
那么有没有更好的 SQL 解决方案不能使用游标?
更新
目前我测试了所有给定的答案。通过阅读,它们看起来都很好,并且有一些有趣的方法。不幸的是,所有这些(到目前为止)在真实数据上都失败了。最大的问题似乎是数据的海量(目前它们在表中大约有 350 万个条目)。仅对一小部分子集执行给定查询会产生预期的结果,但将查询滚动到整个表只会导致非常糟糕的性能。
我必须进一步测试和检查我是否可以对数据进行分块,并且只将部分数据传递给这些给定算法之一以使这件事滚动起来。但也许你们中的某个人有另一个聪明的想法,可以更快地获得结果。
更新(有关结构的更多信息)
好的,这些信息也可能会有所帮助: 目前,表中约有 350 万个条目。以下是给定的列类型和索引:
- _ID
- int
- 主键
- 分组索引
- 在我的示例中没有提到此列,因为此查询不需要它
- 设备ID
- int
- 不为空
- 索引
- 时间戳
- 日期时间
- 不为空
- 索引
- 价值
- 几个不同类型(int、real、tinyint)的未索引列
- 都可以为空
也许这有助于改进给定问题的现有(或新)解决方案。
【问题讨论】:
-
在这种情况下,开始和结束是否必须以 5 秒为间隔?我的意思是,只要从 1.1.2011 14:23:14 开始的行在 1 到 5 秒内,是否可以以 1.1.2011 14:23:14 开始并以 1.1.2011 14:23:38 结束与上一行的差距?
-
@shahkalpesh:不,它们不需要精确的间隔(实际上它们就像显示在 1-2 秒间隔的某个地方,但有时由于四舍五入会错过一秒) .但是,如果您发现间隙 > 5 秒,则会发生停止/启动。所以你的意思是正确的。
-
此问题的每个解决方案都将“必须检查每一行中的每个值”,因此游标解决方案仍然可能是最有效的。除了游标之外,SQL 没有提供任何方法来指定顺序处理,例如比较每对连续行之间的值(当然是根据某种排序顺序连续的,而不是物理上的磁盘)。
-
关于 _ID 列和索引的信息很重要。据我所知,您的设置由于在 DeviceID 和 Timestamp 列上都缺少索引而引入了额外的低效率。我们都需要它们,并且我们需要按它们对记录进行分组和排序。现在我们不仅需要对记录进行排序(或建立临时查找表),而且在使用任何现有索引时,我们仍然需要在主表中使用 _ID 进行书签查找。 (注意:在查询和数据修改的效率方面,使用聚集索引非常受限制。没有充分理由不应该这样做。)
标签: sql sql-server-2008 gaps-and-islands