2017-10-13 4 views
0

시간 간격으로 총 시간을 분할 :SQL -이처럼 보이는 항목이

사용자 ID를 --- StatusStart --- StatusEnd --- StatusKey --- StateDuration
Joe1 ------ 8:59:46 -------- 9:08:06 ------- 사용 가능 ----- 500

내가해야 할 일은 두 개의 항목으로 나누는 것입니다. 단정도를 8시 59 분 46 초에서 9시 00 분까지 그리고 9시 30 분에서 9시 8 분 06 초까지

궁극적으로 내가 가질 수 있기를 바라고 있습니다. 나는이 정보의 거대한 테이블에 적용 할 수있는 무엇인가 그래서 나는 무엇을 그리고 얼마나 많은 시간이 대리인을 위해 매 30 분을 소비 하는지를 알아낼 수있다. 나는 이것을 잊어 버리고 있습니다, 나는 긍정적입니다. 왜냐하면 나는 매번 웹에 빠지게됩니다. 잊고있는 것이 있어야합니다.

또한 수식이 무엇이든 이상적으로 여러 시간 간격으로 걸쳐 작업하면 이상적입니다. StatusStart는 8:59:46이지만 StatusEnd는 10:08:06입니다.

+1

그리고'StatusEnd'이되는 경우 출력은 무엇인가'10 : 08 : 06'? –

+0

StatusStart 및 StatusEnd 열의 데이터 유형은 무엇입니까? –

+0

이렇게 빨리 많은 훌륭한 반응! 나는 각각을 시험해보고 어느 것이 가장 잘 작동하는지 표시 할 것입니다. 이 사이트는 결코 나를 실망시키지 않습니다. – Anthony

답변

3

올드 스쿨 접근,하지만 두 번째 테이블을 만들 것입니다 :

CREATE TABLE SplitTimes (
    SplitStart time not null, 
    SplitEnd time not null, 
    primary key (SplitStart, SplitEnd) 
) 

를 채울를 :

INSERT INTO SplitTimes (SplitStart, SplitEnd) VALUES 
('0:00', '0:30'), 
('0:30', '1:00'), 
('1:00', '1:30'), 
('1:30', '2:00'), 
('2:00', '2:30'), 
('2:30', '3:00'), 
('3:00', '3:30'), 
('3:30', '4:00'), 
('4:00', '4:30'), 
('4:30', '5:00'), 
('5:00', '5:30'), 
('5:30', '6:00'), 
('6:00', '6:30'), 
('6:30', '7:00'), 
('7:00', '7:30'), 
('7:30', '8:00'), 
('8:00', '8:30'), 
('8:30', '9:00'), 
('9:00', '9:30'), 
('9:30', '10:00'), 
('10:00', '10:30'), 
('10:30', '11:00'), 
('11:00', '11:30'), 
('11:30', '12:00'), 
('12:00', '12:30'), 
('12:30', '13:00'), 
('13:00', '13:30'), 
('13:30', '14:00'), 
('14:00', '14:30'), 
('14:30', '15:00'), 
('15:00', '15:30'), 
('15:30', '16:00'), 
('16:00', '16:30'), 
('16:30', '17:00'), 
('17:00', '17:30'), 
('17:30', '18:00'), 
('18:00', '18:30'), 
('18:30', '19:00'), 
('19:00', '19:30'), 
('19:30', '20:00'), 
('20:00', '20:30'), 
('20:30', '21:00'), 
('21:00', '21:30'), 
('21:30', '22:00'), 
('22:00', '22:30'), 
('22:30', '23:00'), 
('23:00', '23:30'), 
('23:30', '23:59:59.9999999'); 

지금이 실행할 수 있습니다

SELECT e.UserID 
    ,case when e.StatusStart >= t.SplitStart then e.StatusStart else t.SplitStart end as SplitStatusStart 
    ,case when e.StatusEnd <= t.SplitEnd then e.StatusEnd else t.SplitEnd end as SplitStatusEnd 
    ,e.StatusKey 
    ,datediff(second, case when e.StatusStart >= t.SplitStart then e.StatusStart else t.SplitStart end, 
     case when e.StatusEnd <= t.SplitEnd then e.StatusEnd else t.SplitEnd end) SplitStatusDuration 
FROM EntryTable e 
INNER JOIN SplitTimes t 
    ON e.StatusStart <= t.SplitEnd 
    AND e.StatusEnd >= t.SplitStart 

를이 시간 대신 datetimes로 작업 할 수 있으며 자정을 넘어 작업하도록 만들 수 있습니다. 그것은 날짜에서 시간을 떼어 내고 다른 하나를 다시 추가하는 것입니다.

큰 테이블에서 성능이 좋은 재귀 CTE가 아니라는 장점이 있습니다.

+0

이것이 OP가 요청한 것과 같이 실제로 반 시간으로 나뉘는 유일한 대답이라고 생각합니다. –

+0

지금까지이 코드는 아주 잘 작동합니다. 테이블을 생성하는 것은 나에게 일어나지도 않았으며, 다른 프로세스에서이 작업을 수행 한 이후로 테이블을 작성하는 것은별로 중요하지 않습니다. 당신이 고급 초보자이고 이미 미친 일 주일을 다룰 때 어떻게됩니까? 고마워요 베이컨 비트! – Anthony

0

당신은이 같은 recursive CTE를 사용할 수 있습니다

열팽창 계수는 시작 시간과 다음 시간을 선택
create table #temp (UserID nvarchar(100), StatusStart time, StatusEnd time, StatusKey nvarchar(100), StateDuration int) 
insert into #temp (UserID, StatusStart, StatusEnd, StatusKey, StateDuration) values 
    ('Joe1', '8:59:46', '9:08:06', 'Available', 500), 
    ('Joe2', '8:59:46', '10:08:06', 'Available', 500) 

;WITH cte AS (
    SELECT UserID, StatusStart, CONVERT(time, DATEADD(hour, DATEDIFF(hour, 0, StatusStart) + 1, 0)) AS t, StatusEnd, StatusKey, StateDuration FROM #temp 
    UNION ALL 
    SELECT UserID, t, CONVERT(time, DATEADD(hour, 1, t)) AS t, StatusEnd, StatusKey, StateDuration FROM cte 
    WHERE t < StatusEnd 
) 
SELECT UserID, StatusStart, CASE WHEN t > StatusEnd THEN StatusEnd ELSE t END AS t, StatusKey, StateDuration FROM cte ORDER BY UserID, t 

drop table #temp 

다음 다음 시간이 클 때까지, 다음 시작 시간으로 마지막 시간을 사용하여 자체 조합 StatusEnd보다. DATEADDdatetimes을 반환하기 때문에 거기에 time으로 변환해야합니다.

결과 :

enter image description here

0

또 다른 옵션

Declare @YourTable Table ([UserID] varchar(50),[StatusStart] time,[StatusEnd] time,[StatusKey] varchar(50),[StateDuration] int) 
Insert Into @YourTable Values 
('Joe1','8:59:46','9:08:06','Available',500) 
,('ZZZZ','8:59:46','10:08:06','Available',500) -- Added multi hour 


Select A.UserID 
     ,StatusStart = convert(time,IIF(DatePart(HOUR,A.StatusStart)=H,StatusStart,DateAdd(HOUR,H,0))) 
     ,StatusEnd = convert(time,IIF(DatePart(HOUR,A.StatusStart)=H ,DateAdd(HOUR,H+1,0),IIF(H<DatePart(HOUR,StatusEnd),DateAdd(HOUR,H+1,0),StatusEnd))) 
     ,A.StatusKey 
     ,A.StateDuration 
From @YourTable A 
Join (
     Select Top 24 H=-1+Row_Number() Over (Order By (Select NULL)) 
     From master..spt_values n1 
    ) B on H between DatePart(HOUR,A.StatusStart) and DatePart(HOUR,A.StatusEnd) 

반환

enter image description here

0

숫자 표를 사용하여 시간 세그먼트를 만드는 인라인 테이블 값 함수 솔루션입니다. 테스트 케이스가있는 샘플 테이블을 만들어 각 요청에 대한 출력을 보여줍니다.

DROP FUNCTION IF EXISTS itvf_Segments; 
GO 

CREATE FUNCTION itvf_Segments(@start TIME,@end TIME) 
RETURNS TABLE 
AS 
RETURN 
(
    WITH N1 (Number) AS (SELECT 1 UNION ALL SELECT 1) 
     ,N2 (Number) AS (SELECT 1 FROM N1 CROSS JOIN N1 AS N2) 
     ,N3 (Number) AS (SELECT 1 FROM N2 CROSS JOIN N2 AS N3) 
     ,N4 (Number) AS (SELECT 1 FROM N3 CROSS JOIN N3 AS N4) 
     ,Numbers (Number) AS (SELECT TOP 48 ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 FROM N4) 
     ,Times (StartTime,EndTime) AS (SELECT TIMEFROMPARTS(Number/2,Number%2*30,0,0,0),DATEADD(minute,30,TIMEFROMPARTS(Number/2,Number%2*30,0,0,0)) FROM Numbers) 
    SELECT 
     CASE WHEN @start > T.StartTime THEN @start ELSE T.StartTime END AS NewStatusStart 
     ,CASE WHEN @end < T.EndTime THEN @end ELSE T.EndTime END AS NewStatusEnd 
    FROM Times AS T 
    WHERE @start <= T.EndTime 
     AND @end >= T.StartTime 
) 
GO 
; 

DROP TABLE IF EXISTS UserStatus; 

CREATE TABLE UserStatus 
(
    UserID VARCHAR(10) 
    ,StatusStart TIME 
    ,StatusEnd TIME 
    ,StatusKey VARCHAR(25) 
    ,StateDuration SMALLINT 
) 
; 

INSERT INTO UserStatus 
(UserID,StatusStart,StatusEnd,StatusKey,StateDuration) 
VALUES 
('Joe1','08:59:46','09:08:06','Available',500) 
,('Joe2','08:59:46','10:08:06','Available',500) 
; 

SELECT * 
FROM UserStatus 
    CROSS APPLY itvf_Segments(StatusStart,StatusEnd) 
ORDER BY UserID,NewStatusStart,NewStatusEnd 
; 

enter image description here

관련 문제