2016-05-26 6 views
3

Итак, у меня есть таблица с рядами, как это:Как сгруппировать последовательные строки?

Ev_Message  Ev_Comment    EV_Custom1   Ev_Time_Ms  
------------------------------------------------------------------------------------- 
Machine 1 Alarm 5/23/2016 11:02:00 AM Alarms Scanned  25    
Machine 1 Alarm 5/23/2016 11:00:00 AM Alarms Scanned  686 
Machine 1 Alarm 5/23/2016 11:00:00 AM Light curtain  537 
Machine 1 Alarm 5/23/2016 11:00:00 AM Guard door open  346 
Machine 1 Alarm 5/23/2016 11:00:00 AM No control voltage 135 
Machine 1 Alarm 5/23/2016 10:38:34 AM Alarms Scanned  269 
Machine 1 Alarm 5/23/2016 10:38:29 AM Alarms Scanned  378 
Machine 1 Alarm 5/23/2016 10:38:29 AM Guard door open  156 
Machine 1 Alarm 5/23/2016 10:38:25 AM Alarms Scanned  654 
Not an Alarm  5/23/2016 10:38:25 AM Not an Alarm   467  
Machine 1 Alarm 5/23/2016 10:38:25 AM Guard door open  234 
Machine 1 Alarm 5/23/2016 10:38:25 AM No control voltage 67 
Machine 1 Alarm 5/23/2016 10:38:23 AM Alarms Scanned  124 
Machine 1 Alarm 5/23/2016 10:38:23 AM No control voltage 100 

An «Alarms Отсканированные» строка добавляется каждый раз, когда сигналы проверяются на который каждый раз, когда сигнал тревоги или очищается. Любые аварийные сигналы добавят строку с определенным Ev_Custom1. первый столбец Ev_Message содержит идентификатор машины, который позволяет мне выделять аварийные сигналы с разных компьютеров. (не любите ли вы имена произвольных столбцов?) Есть более девятисот уникальных тревожных сообщений.

То, что я хочу, чтобы мой запрос, чтобы вернуть что-то вроде этого:

Alarm Message  Alarm Start Time  Alarm Stop Time 
---------------------------------------------------------------- 
No control voltage 5/23/2016 10:38:23 AM 5/23/2016 10:38:29 AM 
Guard door open  5/23/2016 10:38:25 AM 5/23/2016 10:38:34 AM 
No control voltage 5/23/2016 11:00:00 AM 5/23/2016 11:02:00 AM 
Guard door open  5/23/2016 11:00:00 AM 5/23/2016 11:02:00 AM 
Light curtain  5/23/2016 11:00:00 AM 5/23/2016 11:02:00 AM 

Это будет запрос фильтруется между двумя датами. У меня есть возможность изменить данные, поступающие в таблицу, но с 900 тревогами моя свобода ограничена.

С некоторой помощью, мой текущий запрос заключается в следующем:

WITH T AS (
    SELECT  s.Ev_Comment AS start_time, 
       MIN(COALESCE (e.Ev_Comment, s.Ev_Comment)) AS end_time 
    FROM  A AS s 
    INNER JOIN A AS e 
      ON s.Ev_Comment < e.Ev_Comment 
      AND s.Ev_Custom1 = 'Alarms Scanned' 
      AND e.Ev_Custom1 = 'Alarms Scanned' 
    GROUP BY s.Ev_Comment) 
SELECT  T_1.start_time, 
      T_1.end_time, 
      A.Ev_Custom1 
FROM  A 
INNER JOIN T AS T_1 
     ON A.Ev_Comment LIKE T_1.start_time 
WHERE  (A.Ev_Custom1 <> 'Alarms Scanned') 

Я до сих пор есть одна проблема. если тревога длится дольше, чем один период, как «Гвардия дверь открытой» от 10:38:25 до 10:38:34, то он будет отображаться в двух отдельных линий, например, так:

start_time    end_time    EV_Custom1 
--------------------- --------------------- ------------- 
5/23/2016 10:38:25 AM 5/23/2016 10:38:29 AM Guard door open 
5/23/2016 10:38:29 AM 5/23/2016 10:38:34 AM Guard door open 

Когда в идеале, что Я хочу это:

start_time    end_time    EV_Custom1 
--------------------- --------------------- ------------- 
5/23/2016 10:38:25 AM 5/23/2016 10:38:34 AM Guard door open 

Я думаю, что нужно group by ((Ev_custom1) and (when end_time = start_time)) (простите мой псевдо-код), но я не знаю достаточно о синтаксисе, необходимом для этого не знаю.

Here is an SQLFiddle

+2

Как вы получаете значения для периода остановки сигнала тревоги? – techspider

+0

- это временная метка строки «Отсканированная проверка», которая не имеет тревоги с одинаковой отметкой времени. что во время этого сканирования сигнал тревоги не был найден. –

+0

Я добавил важность столбца Ev_Message для запроса –

ответ

2

Если я понимаю правильно отправили проблему, то ваш CTE эффективно определяет время ведра (или интервалы) для всех ваших тревог. Ваше окончательное предложение select объединяет фактическую информацию о тревоге с вашими интервалами тревоги. Часть вашей проблемы заключается в том, что ваша тревожная система будет продолжать регистрировать записи «Тревоги отсканированы», если ваш сигнал остается активным в течение продолжительных периодов времени (я предполагаю дольше, чем цикл проверки тревоги), что эффективно приводит к разделению активных аварийных сигналов. Если у вас есть SQL Server 2012 или выше, то относительно легко определить, произошло ли событие тревоги. Вам просто нужно проверить, соответствует ли время окончания сигнала тревоги времени запуска следующего сигнала тревоги с тем же типом сигнала тревоги. Вы можете добиться этого с помощью функции оконной обработки LAG в 2012 году.
Следующим шагом является создание идентификатора, с помощью которого вы можете группировать свой сигнал тревоги, чтобы вы могли комбинировать раздельные события. Это достигается с помощью предложения SUM OVER. Следующий пример показывает, как это может быть достигнуто:

;WITH AlarmTimeBuckets 
AS 
(
    SELECT  EventStart.Ev_Comment AS StartDateTime 
       ,MIN(COALESCE (EventEnd.Ev_Comment, EventStart.Ev_Comment)) AS EndDateTime 
       ,EventStart.Ev_Message As Machine 
    FROM   A EventStart 
    INNER JOIN A EventEnd ON EventStart.Ev_Comment < EventEnd.Ev_Comment AND EventStart.Ev_Custom1 = 'Alarms Scanned' AND EventEnd.Ev_Custom1 = 'Alarms Scanned' AND EventStart.Ev_Message = EventEnd.Ev_Message 
    GROUP BY  EventStart.Ev_Message, EventStart.Ev_Comment 
), 
AlarmsByTimeBucket 
AS 
(
    SELECT  AlarmTimeBuckets.Machine 
       ,AlarmTimeBuckets.StartDateTime 
       ,AlarmTimeBuckets.EndDateTime 
       ,Alarm.Ev_Custom1 AS Alarm 
       ,(
       CASE 
        WHEN LAG(AlarmTimeBuckets.EndDateTime, 1, NULL) OVER (PARTITION BY Alarm.Ev_Custom1,Alarm.Ev_Message ORDER BY AlarmTimeBuckets.StartDateTime) = AlarmTimeBuckets.StartDateTime THEN 0 
        ELSE 1 
       END 
       ) AS IsNewEvent 
    FROM  A Alarm 
    INNER JOIN AlarmTimeBuckets ON Alarm.Ev_Message = AlarmTimeBuckets.Machine AND Alarm.Ev_Comment = AlarmTimeBuckets.StartDateTime 
    WHERE  (Alarm.Ev_Custom1 <> 'Alarms Scanned') 
) 
, 
AlarmsByGroupingID 
AS 
(
    SELECT Machine 
      ,StartDateTime 
      ,EndDateTime 
      ,Alarm 
      ,SUM(IsNewEvent) OVER (ORDER BY Machine, Alarm, StartDateTime) AS GroupingID 
    FROM AlarmsByTimeBucket 
) 
SELECT  MAX(Machine) AS Machine 
      ,MIN(StartDateTime) AS StartDateTime 
      ,MAX(EndDateTime) AS EndDateTime 
      ,MAX(Alarm) AS Alarm 
FROM  AlarmsByGroupingID 
GROUP BY GroupingID 
ORDER BY StartDateTime 
+0

получается, что я использую SQL Server 2012. Я просматриваю Microsoft Visual Studio 2010 с помощью служб отчетов SQL Server. я скопировал ваш ответ в стенограмме, и он дал мне именно то, что я хотел. –

+0

Я был неправ. вам не удалось учесть первый столбец Ev_Message. этот столбец содержит идентификатор машины, который позволяет мне выделять аварийные сигналы с разных компьютеров. (не любите ли вы имена произвольных столбцов?) ваш запрос не смотрит на этот столбец. я посмотрю, могу ли я сам ее подделать. –

+0

@TylerLillemo, пожалуйста, обновите свое оригинальное сообщение, чтобы отразить важность EV_Message, так как вы впервые упомянули об этом. –

1

Я обновил свой sqlfiddle ссылку, а с версиями ниже. В вашем окончательном наборе результатов вам нужно установить row_number и присоединиться к нему на EV_CUSTOM1, START_TIME = END_TIME (как вы подозревали), а также номер строки = номер строки + 1. Вот как вы можете определить, являются ли два события за тот же период. Это было бы немного проще, если бы вы были на Sql Server 2012+, где у вас есть функции LAG/LEAD, доступные, как указал @EdmondQuinton в его ответе.

WITH T AS (SELECT s.Ev_Comment AS start_time, MIN(COALESCE (e.Ev_Comment, s.Ev_Comment)) AS end_time   
      FROM A AS s 
      INNER JOIN A AS e 
      ON s.Ev_Comment < e.Ev_Comment 
      AND s.Ev_Custom1 = 'Alarms Scanned' 
      AND e.Ev_Custom1 = 'Alarms Scanned' 
      GROUP BY s.Ev_Comment 
     ), 

T2 AS(SELECT T_1.start_time, T_1.end_time, A.Ev_Custom1, 
      ROW_NUMBER() OVER (PARTITION BY EV_CUSTOM1 ORDER BY T_1.START_TIME) RN 
     FROM A 
     INNER JOIN 
     T AS T_1 
     ON A.Ev_Comment LIKE T_1.start_time 
     WHERE (A.Ev_Custom1 <> 'Alarms Scanned') 
    ) 

select 
    coalesce(b.START_TIME, a.START_TIME) START_TIME, 
    max(a.END_TIME) END_TIME, 
    a.EV_CUSTOM1 
from T2 a 
left outer join T2 b 
on a.EV_CUSTOM1 = b.EV_CUSTOM1 
and a.START_TIME = b.END_TIME 
and a.RN = b.RN+1 
group by coalesce(b.START_TIME, a.START_TIME), 
     a.EV_CUSTOM1 
+1

благодарю вас за ответ, он тоже работает. Мне пришлось добавить инструкцию WHERE между первой «внутренней связью» и «группой» 'похоже на сообщение @EdmondQuinton, извинения за то, что я не понял, что мне это нужно. –

+0

по какой-то причине я получаю две отдельные строки для аварийных сообщений чем один день. Решение @EdmondQuinton не имеет этой проблемы. –

+0

Я не могу воспроизвести это. Из ваших выборочных данных, если я изменю окончательный сигнал тревоги с '5/23/2016 11:02:00 AM' до' 25/24/2016 11:02:00 AM', он все еще работает нормально. Я могу посмотреть, если у вас есть дополнительные данные, но похоже, что у вас уже есть рабочее решение. – mo2