根据特定的开始/结束值过滤数据并计算时间

问题描述 投票:0回答:1

我在过滤出特定数据集以捕获子集并计算该子集的持续时间时遇到麻烦。

我们有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

任何帮助/指导将不胜感激。谢谢!

sql-server tsql ssms
1个回答
0
投票

我对这个问题的解决方法是弄清最后一个窗口的“活动”是什么,并基于此进行过滤。请注意,为方便起见,我对数据类型进行了一些细微更改-我已将日期和时间列转换为单个日期时间,并将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事件。

请注意,不幸的是,由于存在交叉联接,对于大数据集,此查询可能会变慢。

© www.soinside.com 2019 - 2024. All rights reserved.