2016-10-06 9 views
2

私は、異なるシステムとその状況を別の時間に取得した情報を格納する3つの列(マシン、時間、ステータス)を持つテーブルを持っています。連続した出現の開始と終了を取得する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以降を使用している場合:場合

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

ありがとうShishir。この解決策は私にも期待された結果をもたらしました。私は私と一緒に2012年のインスタンスを持っています。だから最初の解決策になるでしょう。あなたのソリューションは私が以前のバージョンを持っていた場合にそれを行う方法を理解するのに役立ちました。 –

関連する問題