2016-07-18 8 views
0

DayIDで注釈が付けられた特定の日の1時間に1つずつ、24個のエントリを含む一時テーブルがあります。この表には、特定の時間帯にアプリケーションがオンであるかオフであるかを示す情報が含まれています。SQLサーバー:開始時刻と終了時刻を含むテーブルから日付範囲を作成する方法

テーブル内のエントリ数を減らして、アプリケーションがオンになっている時間だけを表示したいとします。

いくつかのサンプルデータは、次のとおりです。

CREATE TABLE #OnOff 
(
    RowID INT identity(1, 1), 
    DayID TINYINT, 
    OnOff BIT, 
    StartTime TIME, 
    EndTime TIME 
) 

INSERT INTO #OnOff (DayID, OnOff, StartTime, EndTime) VALUES 
(1, 0, '00:00', '00:59'), 
(1, 0, '01:00', '01:59'), 
(1, 0, '02:00', '02:59'), 
(1, 1, '03:00', '03:59'), 
(1, 1, '04:00', '04:59'), 
(1, 0, '05:00', '05:59'), 
(1, 1, '06:00', '06:59'), 
(1, 1, '07:00', '07:59'), 
(1, 0, '08:00', '08:59'), 
(1, 0, '09:00', '09:59'), 
(1, 0, '10:00', '10:59'), 
(1, 0, '11:00', '11:59'), 
(1, 0, '12:00', '12:59'), 
(1, 0, '13:00', '13:59'), 
(1, 1, '14:00', '14:59'), 
(1, 1, '15:00', '15:59'), 
(1, 1, '16:00', '16:59'), 
(1, 0, '17:00', '17:59'), 
(1, 0, '18:00', '18:59'), 
(1, 0, '19:00', '19:59'), 
(1, 0, '20:00', '20:59'), 
(1, 0, '21:00', '21:59'), 
(1, 0, '22:00', '22:59'), 
(1, 0, '23:00', '23:59') 

を所望の出力は#OnOffテーブルは常にその日の時間ごとの値が含まれている(すなわちエンドと時刻を開始します

DayID StartTime EndTime 
1  03:00  04:59 
1  06:00  07:59 
1  14:00  16:59 

する必要があります最後の1時間を除いて常に連続している)。明らかにこれをカーソルで実現することはできますが、これは非常に非効率的です。この結果を達成するためのよりよい方法がありますか?

+0

あなたの質問はあまり明確ではありません。 'OnOff'の値が1の行だけを挿入するのはなぜですか? –

+0

あなたが表示した時間範囲を使用することを忘れないでください。 'timenow <= '16:59 'は' timenow <17:00'とほぼ1分異なります。 –

+0

@Ollieコメントありがとうございました。この例では、頻度は60秒未満で管理することができますが、私は原則に同意します – Gert

答えて

2

あなたはデータセット上でCTEを使用することにより、所望の結果を達成することができます

CREATE TABLE #OnOff 
    (
     RowID INT IDENTITY(1, 1) , 
     DayID TINYINT , 
     OnOff BIT , 
     StartTime TIME , 
     EndTime TIME 
    ) 

INSERT INTO #OnOff 
     (DayID, OnOff, StartTime, EndTime) 
VALUES (1, 0, '00:00', '00:59'), 
     (1, 0, '01:00', '01:59'), 
     (1, 0, '02:00', '02:59'), 
     (1, 1, '03:00', '03:59'), 
     (1, 1, '04:00', '04:59'), 
     (1, 0, '05:00', '05:59'), 
     (1, 1, '06:00', '06:59'), 
     (1, 1, '07:00', '07:59'), 
     (1, 0, '08:00', '08:59'), 
     (1, 0, '09:00', '09:59'), 
     (1, 0, '10:00', '10:59'), 
     (1, 0, '11:00', '11:59'), 
     (1, 0, '12:00', '12:59'), 
     (1, 0, '13:00', '13:59'), 
     (1, 1, '14:00', '14:59'), 
     (1, 1, '15:00', '15:59'), 
     (1, 1, '16:00', '16:59'), 
     (1, 0, '17:00', '17:59'), 
     (1, 0, '18:00', '18:59'), 
     (1, 0, '19:00', '19:59'), 
     (1, 0, '20:00', '20:59'), 
     (1, 0, '21:00', '21:59'), 
     (1, 0, '22:00', '22:59'), 
     (1, 0, '23:00', '23:59') 

;WITH cte 
    AS (-- Get the first row, seed for the cte, set the OnOffGroup to 1 
     SELECT TOP 1 
       RowID , DayID , OnOff , StartTime , EndTime , 1 AS OnOffGroup 
     FROM  #OnOff 
     WHERE OnOff = 1 
     ORDER BY RowID 
     UNION ALL 
     -- Join latest cte row with next row in sequence, 
     -- OnOffGroup set to previous row value if state matches, otherwise increment 
     SELECT #OnOff.RowID , #OnOff.DayID , #OnOff.OnOff , 
       #OnOff.StartTime , #OnOff.EndTime , 
       CASE WHEN #OnOff.OnOff = 1 THEN cte.OnOffGroup 
         ELSE cte.OnOffGroup + 1 
       END AS OnOffGroup 
     FROM  #OnOff 
       INNER JOIN cte ON cte.RowID + 1 = #OnOff.RowID 
     ) 
    -- Output results with grouping and min/max to produce desired results 
    SELECT cte.DayID , 
      MIN(cte.StartTime) AS StartTime , 
      MAX(cte.EndTime) AS EndTime , 
      cte.OnOffGroup 
    FROM cte 
    WHERE cte.OnOff = 1 
    GROUP BY cte.DayID , 
      cte.OnOffGroup 

が生成されます

DayID StartTime   EndTime    OnOffGroup 
1  03:00:00.0000000 04:59:00.0000000 1 
1  06:00:00.0000000 07:59:00.0000000 2 
1  14:00:00.0000000 16:59:00.0000000 8 
+0

ご協力いただきありがとうございます。これはうまくいった。 – Gert

1

OUTERが適用とDENSE_RANKとのもう一つの方法:

;WITH cte AS (
SELECT o.StartTime, 
     o.EndTime, 
     DENSE_RANK() OVER (ORDER BY r.EndTime) as DR 
FROM #OnOff o 
OUTER APPLY (
      SELECT top 1 * 
      FROM #OnOff 
      WHERE o.EndTime < EndTime and OnOff = 0 
      ) as r 
WHERE o.OnOff = 1 
) 

SELECT MIN(StartTime) as StartTime, 
     MAX(EndTime) as EndTime 
FROM cte 
GROUP BY DR 

出力を:

StartTime   EndTime 
03:00:00.0000000 04:59:59.0000000 
06:00:00.0000000 07:59:59.0000000 
14:00:00.0000000 16:59:59.0000000 
+0

ご協力いただきありがとうございます。これはうまくいき、他の日に追加のdayIDを追加するのはかなり簡単でした。 – Gert

関連する問題