0

DayID で注釈が付けられた特定の日の 1 時間ごとに 1 つずつ、24 のエントリを含む一時テーブルがあります。テーブルには、その特定の時間範囲でアプリケーションがオンかオフかが示されます。

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

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

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')

望ましい出力は

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

#OnOff テーブルには、常に 1 日のすべての時間の値が含まれます (つまり、最後の 1 時間を除いて、終了時刻と開始時刻は常に連続します)。明らかにカーソルを使用してこれを実現できますが、これは非常に非効率的です。この結果を達成するためのより良い方法はありますか。

4

2 に答える 2

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
于 2016-07-18T10:25:15.767 に答える
1

OUTER APPLY と 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
于 2016-07-18T10:42:38.357 に答える