【发布时间】:2021-02-13 13:09:12
【问题描述】:
在 SQL Server 中,我有一组时间序列开/关事件,如下所示(为简单起见,我只显示了一个警报编号,但同一张表中有很多):
'Alarms' Table:
AlarmNumber Time AlarmState
1592 2020-01-02 01:52:02 1
1592 2020-01-02 01:58:07 0
1592 2020-04-28 03:46:49 1
1592 2020-04-28 06:19:10 0
1592 2020-06-04 00:25:22 1
1592 2020-08-27 01:57:03 1
1592 2020-08-27 05:16:32 0
1592 2020-09-17 02:51:57 0
我正在尝试将其转换为开/关对:
Output I am trying to achieve, ideally as an SQL View:
AlarmNumber StartTime EndTime
1592 2020-01-02 01:52:02 2020-01-02 01:58:07
1592 2020-04-28 03:46:49 2020-04-28 06:19:10
1592 2020-06-04 00:25:22 NULL
1592 2020-08-27 01:57:03 2020-08-27 05:16:32
1592 NULL 2020-09-17 02:51:57
如果我有一个干净的数据集,没有丢失“开启”或“关闭”事件,我可以通过以下方式实现:
select tOn.AlarmNumber, tOn.Time StartTime, tOff.Time EndTime
from (
select AlarmNumber, Time,
ROW_NUMBER() Over(Partition by AlarmNumber order by Time) EventID
from Alarms where AlarmState = 1
) tOn
LEFT JOIN (
select AlarmNumber, Time,
ROW_NUMBER() Over(Partition by AlarmNumber order by Time) EventID
from Alarms where AlarmState = 0
) tOff
on (tOn.AlarmNumber = tOff.AlarmNumber and tOn.EventID = tOff.EventID)
(代码修改自 Adriano Carneiro 在T-SQL Start and end date times from a single column 的回答)
我的问题:谁能想到一种处理“警报”表的有效方法来实现我的示例输出,它处理丢失的开/关事件(在示例输出中显示为 NULL)?
我的备份是使用 Cursor 和 Where 循环,但我希望有一种方法可以将成对的 On/Off 事件组合在一起,但我无法让它工作。我有超过 500k 的事件,所以这是一个需要迭代的大型数据集。
欢迎任何想法!
谢谢你, 托马斯
------ 2020 年 11 月 1 日更新 ------
我们提供了两种出色的解决方案,它们都可以正常工作,并在 80,000 行杂乱的现实世界数据的样本中提供相同的结果。
- GMB 的解决方案阅读起来更简单,但运行起来有点慢
- gotqn 的解决方案是代码行更多,但在我的测试服务器上运行速度提高了 50% 左右
【问题讨论】:
标签: sql sql-server tsql datetime gaps-and-islands