我在过滤出特定数据集以捕获子集并计算该子集的持续时间时遇到麻烦。
我们有PC,可以在某些任务打开时进行记录;何时打开电源,何时加载BIOS,何时启动Windows,何时启动应用程序等-以及这些任务何时关闭。我的目标是围绕何时打开窗户以及在关闭窗户之前打开/关闭哪些任务以及窗户打开/关闭的持续时间。
原始数据集:
PCNum Code On/Off Date Time
1. 5258 power on 10/11/2019 10:00:00
2. 5258 bios on 10/11/2019 10:00:10
3. 5258 windows on 10/11/2019 10:00:20
4. 5258 steam on 10/11/2019 10:00:55
5. 5258 origin on 10/11/2019 10:01:03
6. 5258 origin off 10/11/2019 10:10:04
7. 5258 steam off 10/11/2019 10:12:45
8. 5258 windows off 10/11/2019 10:13:06
9. 5258 bios off 10/11/2019 10:14:01
10. 5258 power off 10/11/2019 10:14:22
11. 5258 power on 10/11/2019 11:34:45
12. 5258 bios on 10/11/2019 11:34:56
13. 5258 windows on 10/11/2019 11:35:03
14. 5258 skype on 10/11/2019 11:35:06
15. 5258 skype off 10/11/2019 11:56:52
16. 5258 windows off 10/11/2019 11:57:07
17. 5258 bios off 10/11/2019 11:57:36
18. 5258 power off 10/11/2019 11:57:48
使用CTE,我已经能够过滤我的数据,因此当窗口打开时它会拉动第一个迭代,而当窗口关闭时它会拉动最后一个迭代,如下所示:
PCNum Code On/Off Date Time
1. 5258 windows on 10/11/2019 10:00:20
2. 5258 steam on 10/11/2019 10:00:55
3. 5258 origin on 10/11/2019 10:01:03
4. 5258 origin off 10/11/2019 10:10:04
5. 5258 steam off 10/11/2019 10:12:45
6. 5258 windows off 10/11/2019 10:13:06
7. 5258 bios off 10/11/2019 10:14:01
8. 5258 power off 10/11/2019 10:14:22
9. 5258 power on 10/11/2019 11:34:45
10. 5258 bios on 10/11/2019 11:34:56
11. 5258 windows on 10/11/2019 11:35:03
12. 5258 skype on 10/11/2019 11:35:06
13. 5258 skype off 10/11/2019 11:56:52
14. 5258 windows off 10/11/2019 11:57:07
现在,我需要进一步过滤设置,以排除在关闭窗口和再次打开窗口之间的所有任务。在这种情况下,它将删除记录7、8、9和10。我还需要计算从打开窗口到关闭窗口的持续时间。
这是我想要的结果:
PCNum Code On/Off Date Time DurationOfWindowsSec
1. 5258 windows on 10/11/2019 10:00:20 0:12:46
2. 5258 steam on 10/11/2019 10:00:55 0:12:46
3. 5258 origin on 10/11/2019 10:01:03 0:12:46
4. 5258 origin off 10/11/2019 10:10:04 0:12:46
5. 5258 steam off 10/11/2019 10:12:45 0:12:46
6. 5258 windows off 10/11/2019 10:13:06 0:12:46
7. 5258 windows on 10/11/2019 11:35:03 0:22:04
8. 5258 skype on 10/11/2019 11:35:06 0:22:04
9. 5258 skype off 10/11/2019 11:56:52 0:22:04
10. 5258 windows off 10/11/2019 11:57:07 0:22:04
任何帮助/指导将不胜感激。谢谢!
我对这个问题的解决方法是弄清最后一个窗口的“活动”是什么,并基于此进行过滤。请注意,为方便起见,我对数据类型进行了一些细微更改-我已将日期和时间列转换为单个日期时间,并将OnOff转换为位列。
SQL Fiddle /数据定义:
create table #test(
id int primary key identity,
PCNum int,
Code varchar(50),
OnOff bit,
dt datetime
)
;
insert into #test(PCNum, Code, OnOff, dt)
values
(5258, 'windows' , 1, '10/11/2019 10:00:20'),
(5258, 'steam' , 1, '10/11/2019 10:00:55'),
(5258, 'origin' , 1, '10/11/2019 10:01:03'),
(5258, 'origin' , 0, '10/11/2019 10:10:04'),
(5258, 'steam' , 0, '10/11/2019 10:12:45'),
(5258, 'windows' , 0, '10/11/2019 10:13:06'),
(5258, 'bios' , 0, '10/11/2019 10:14:01'),
(5258, 'power' , 0, '10/11/2019 10:14:22'),
(5258, 'power' , 1, '10/11/2019 11:34:45'),
(5258, 'bios' , 1, '10/11/2019 11:34:56'),
(5258, 'windows' , 1, '10/11/2019 11:35:03'),
(5258, 'skype' , 1, '10/11/2019 11:35:06'),
(5258, 'skype' , 0, '10/11/2019 11:56:52'),
(5258, 'windows' , 0, '10/11/2019 11:57:07')
;
实际查询:
with last_windows(id, dt) as
(
select t1.id, max(t2.dt) as dt from #test as t1
cross join #test as t2
where datediff(second, t1.dt, t2.dt) <= 0
and t2.code = 'windows'
group by t1.id
),
windows_active(OnOff, dt) as
(
select OnOff, dt
from #test
where Code = 'windows'
)
select *
from #test as t
left join last_windows as w on w.id = t.id
left join windows_active as wa on wa.dt = w.dt
where wa.OnOff = 1
or t.Code = 'windows'
;
说明:last_windows
将表与自身交叉连接,以便找到每一行的最新Windows活动时间。 windows_active
将实际的开/关状态添加到last_windows
,以解决只能通过分组方式选择聚合的问题。
最后,查询将两个CTE连接到原始测试表,并在最后一个Windows事件为'on'的情况下进行过滤。这也可以过滤掉所有关闭Windows的情况,因此有一个or语句可以包含所有Windows事件。
请注意,不幸的是,由于存在交叉联接,对于大数据集,此查询可能会变慢。