0

我有一个包含 24 个条目的临时表,每个条目对应一个由 DayID 注释的特定日期的每个小时。该表包含在该特定时间范围内应用程序是打开还是关闭的指示。

我想减少表中的条目数,只显示应用程序应该打开的时间。

部分样本数据如下:

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 表将始终包含一天中每个小时的值(即结束时间和开始时间总是连续的,除了最后一小时)。显然可以使用游标来实现这一点,但这似乎效率很低。有没有更好的方法来达到这个结果。

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 回答