Фильтрация данных по определенным начальным / конечным значениям и расчет времени - PullRequest
0 голосов
/ 11 октября 2019

У меня проблемы с фильтрацией определенного набора данных для захвата подмножества и расчета длительности этого подмножества.

У нас есть ПК, которые записывают, когда включаются определенные задачи;когда он был включен, когда загружалась биос, когда запускались окна, когда запускались приложения и т. д., а также когда эти задачи выключались. Моя цель сосредоточена на том, когда окна включаются и какие задачи включаются / выключаются до тех пор, пока окна не выключаются, а также на продолжительности включения / выключения окон.

Исходный набор данных:

    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, я смог отфильтровать свои данные, чтобы он включал первую итерацию, когда окна включены, и последнюю итерацию, когда они выключаются, как показано здесь:

with minTime_cte (PCNum, Code, Date, Time)
as
    -- find first occurance of on for windows code
    (select PCNum,
            Code,
            Date,
            Time = min(Time)
    from PCData
    where Code = 'windows' and [On/Off] = 'on'
    group by PCNum, Code),

maxTime_cte (PCNum, Code, Date, Time)
as
    -- find last occurrence of off for windows code
    (select PCNum,
            Code,
            Date,
            Time = max(Time)
    from PCData
    where Code = 'windows' and [On/Off] = 'off'
    group by PCNum, Code),

select PCNum,
       Code,
       [On/Off],
       Date,
       Time
from PCData
  join minTime_cte on minTime_cte.Date = Date
    and minTime_cte.PCNum = PCNum
  join maxTime_cte on maxTime_cte.Date = Date
    and maxTime_cte.PCNum = PCNum
where Time >= minTime_cte.Time
    and Time <= maxTime_cte.Time
order by PCNum, Date, Time
    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

Буду признателен за любую помощь / направление. Спасибо!

1 Ответ

0 голосов
/ 11 октября 2019

Мой подход к этой проблеме - выяснить, каким было последнее событие windows, и отфильтровать его. Если последнее событие было on, то мы должны записать его;в противном случае мы не делаем. В качестве бонуса это означает, что вам может не потребоваться предыдущая предварительная обработка - я не проверял все крайние случаи, но если ваши данные начинаются с выключенного значения windows, то вы должны быть хороши (так что вы можете просто объединиться сфиктивная строка)

Обратите внимание, что для удобства я внес небольшие изменения в типы данных - я преобразовал столбцы даты и времени в один столбец datetime и превратил OnOff в битовый столбец. Оглядываясь назад, возможно, вторая корректировка не была необходима. Получение первой настройки должно быть достаточно простым;Вы могли бы сделать это как часть ваших CTE предварительной обработки.

Я поместил ваши данные во временную таблицу, поэтому мне было легче экспериментировать;вы, вероятно, захотите заменить каждый экземпляр #test именем вашего CTE.

Скрипка SQL / определение данных:

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(id, OnOff) as 
(
select w.id, t.OnOff
from #test as t
    left join last_windows as w on w.dt = t.dt
where t.Code = 'windows'
)
select t.id, t.PCNum, t.Code, t.OnOff, t.dt 
from #test as t
    left join windows_active as wa on wa.id = t.id
where wa.OnOff = 1
    or t.Code = 'windows'
;

Объяснение: CTE last_windows отвечает за определение времени последней windows активности для каждой строки (ID). Это происходит путем перекрестного соединения стола против самого себя. Первый экземпляр называется t1, а второй t2. t2 фильтруется так, чтобы включать только строки windows, а также включать события только в t1 или раньше. Если затем мы берем максимальное t2 datetime для каждого идентификатора в t1, это представляет время последнего windows действия.

Из-за работы агрегатов мы не можем на самом деле добавитьОтключить данные до last_windows. windows_active обеспечивает удобство - он соединяет #test с last_windows, чтобы эффективно добавлять данные OnOff к last_windows. Нам остается таблица, которая сообщает нам, какой была последняя активность windows для каждой строки в #test.

Остальная часть запроса тривиальна - запрос объединяет windows_active в #test и фильтрует только для тех случаев, когда было включено последнее событие windows. Это также отфильтровывает все случаи, когда окна отключаются, поэтому есть оператор or, включающий все windows события.

Обратите внимание, что, к сожалению, из-за перекрестного соединения этот запрос может быть медленным на больших данныхнаборы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...