2016-10-06 3 views
2

У меня есть таблица с 3 столбцами (Machine, Time, Status), которая хранит информацию о разных системах и ее состоянии, записанном в разное время.SQL Server запрос для начала и конца последовательного начала

Machine Time     status 
----------------------------------- 
MAC_1 2016-10-06 06:48 OFF 
MAC_1 2016-10-06 07:48 OFF 
MAC_1 2016-10-06 08:48 ON 
MAC_1 2016-10-06 09:48 ON 
MAC_1 2016-10-06 10:48 ON 
MAC_1 2016-10-06 11:48 OFF 
MAC_1 2016-10-06 12:48 OFF 
MAC_2 2016-10-06 06:48 OFF 
MAC_2 2016-10-06 07:48 OFF 
MAC_2 2016-10-06 08:48 OFF 
MAC_2 2016-10-06 09:48 ON 
MAC_2 2016-10-06 10:48 ON 
MAC_2 2016-10-06 11:48 OFF 

Теперь я пытаюсь получить «последовательное» время OFF и ON для каждой машины.

В результате набор мы пытаемся достичь, как показано ниже,

Machine Status StartTime    EndTime 
----------------------------------------------------------- 
MAC_1  OFF  2016-10-06 06:48  2016-10-06 07:48 
MAC_1  ON  2016-10-06 08:48  2016-10-06 10:48 
MAC_1  OFF  2016-10-06 11:48  2016-10-06 12:48 
MAC_2  OFF  2016-10-06 06:48  2016-10-06 08:48 
MAC_2  ON  2016-10-06 09:48  2016-10-06 10:48 
MAC_2  OFF  2016-10-06 11:48  2016-10-06 11:48 

Пожалуйста, помогите.

С уважением, RON

ответ

2

Это классическая проблема острова данных. Если у вас есть SQL Server 2012 или выше, то вы можете использовать функции Windowing, чтобы получить желаемый результат, как в следующем примере:

DECLARE @MachineStatus TABLE 
(
    [Machine]  NVARCHAR(50) 
    ,[Time]  DATETIME 
    ,[status] NVARCHAR(5) 
    ,PRIMARY KEY([Machine], [Time]) 
) 


INSERT INTO @MachineStatus 
(
    [Machine] 
    ,[Time]  
    ,[status] 
) 
VALUES 
('MAC_1', '2016-10-06 06:48', 'OFF'), 
('MAC_1', '2016-10-06 07:48', 'OFF'), 
('MAC_1', '2016-10-06 08:48', 'ON'), 
('MAC_1', '2016-10-06 09:48', 'ON'), 
('MAC_1', '2016-10-06 10:48', 'ON'), 
('MAC_1', '2016-10-06 11:48', 'OFF'), 
('MAC_1', '2016-10-06 12:48', 'OFF'), 
('MAC_2', '2016-10-06 06:48', 'OFF'), 
('MAC_2', '2016-10-06 07:48', 'OFF'), 
('MAC_2', '2016-10-06 08:48', 'OFF'), 
('MAC_2', '2016-10-06 09:48', 'ON'), 
('MAC_2', '2016-10-06 10:48', 'ON'), 
('MAC_2', '2016-10-06 11:48', 'OFF'); 


WITH CTE_MachineStateChange 
AS 
(
    SELECT [Machine] 
      ,[Time]  
      ,[status] 
      ,(
       CASE 
        WHEN LAG([status], 1, '') OVER (PARTITION BY [Machine] ORDER BY [Time]) <> [status] THEN 1 
        ELSE 0 
       END 
      ) AS [StateChanged] 
    FROM @MachineStatus M 
), CTE_MachineStateGroupByID 
AS 
(
    SELECT [Machine] 
      ,[Time] 
      ,[status] 
      ,SUM([StateChanged]) OVER (PARTITION BY [Machine] ORDER BY [Time] ROWS UNBOUNDED PRECEDING) AS [GroupByID] 
    FROM CTE_MachineStateChange 
) 
SELECT [Machine] 
     ,[status] AS [Status] 
     ,MIN([Time]) AS [StartTime] 
     ,MAX([Time]) AS [EndTime] 
FROM CTE_MachineStateGroupByID 
GROUP BY [Machine], [GroupByID], [status] 
+0

Спасибо Эдмон. Это решение отлично поработало для меня. –

1

В случае, если есть SQL Server 2008.

create table #test(mac varchar(100), mac_dt datetime, mac_stat varchar(100)) 

insert into #test values 
('MAC_1', '2016-10-06 06:48', 'OFF') 
,('MAC_1', '2016-10-06 07:48', 'OFF') 
,('MAC_1', '2016-10-06 08:48', 'ON') 
,('MAC_1', '2016-10-06 09:48', 'ON') 
,('MAC_1', '2016-10-06 10:48', 'ON') 
,('MAC_1', '2016-10-06 11:48', 'OFF') 
,('MAC_1', '2016-10-06 12:48', 'OFF') 
,('MAC_2', '2016-10-06 06:48', 'OFF') 
,('MAC_2', '2016-10-06 07:48', 'OFF') 
,('MAC_2', '2016-10-06 08:48', 'OFF') 
,('MAC_2', '2016-10-06 09:48', 'ON') 
,('MAC_2', '2016-10-06 10:48', 'ON') 
,('MAC_2', '2016-10-06 11:48', 'OFF'); 

with cte as 
(select mac, mac_dt, mac_stat, row_number() over(order by mac, mac_dt) - row_number() over(order by mac, mac_stat) as grp 
from #test) 
select t1.mac Machine, t3.mac_stat [Status], t3.StartTime, t3.EndTime 
from #test t1 cross apply(select t2.mac, min(mac_dt) as StartTime, max(mac_dt) as EndTime, t2.mac_stat 
          from cte t2 
          where t1.mac = t2.mac and t1.mac_stat = t2.mac_stat 
          group by t2.mac, t2.grp, t2.mac_stat) t3 
where t1.mac = t3.mac and t1.mac_stat = t3.mac_stat 
and t1.mac_dt = t3.StartTime            
order by t1.mac, t3.StartTime    
+1

Спасибо, Шишир. Это решение также дало мне ожидаемые результаты. У меня есть экземпляр 2012 года со мной. Так будет идти с первым решением. Ваше решение помогло мне понять, как это сделать, если у нас были более ранние версии. –

Смежные вопросы