2016-07-18 2 views
0

DayID에 의해 주석이 달린 특정 날짜의 시간당 하나씩 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 

해야합니다 것입니다 마지막 시간을 제외하고 항상 연속적이어야 함). 커서로 분명히이를 달성 할 수는 있지만 이것은 비효율적 인 것처럼 보입니다. 이 결과를 얻는 더 좋은 방법이 있습니까?

+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 

는 생산 : OUTER와

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

또 다른 방법 적용 및 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