I am creating a query to get the total hours elapsed in a day by someone, however there can be multiple breaks in the times per day.
Here is the query that I have at the moment.
SELECT
CHINA_VISION_DorEvents.DorCtrls_Ref,
CHINA_VISION_PubCards.CardCode,
CHINA_VISION_DorEvents.EventTM
FROM
CHINA_VISION_PubCards
INNER JOIN
CHINA_VISION_DorEvents ON CHINA_VISION_PubCards.CardCode = CHINA_VISION_DorEvents.CardCode
WHERE
(CHINA_VISION_PubCards.CardCode = '000006f1')
AND CHINA_VISION_DorEvents.DorCtrls_Ref = '16'
ORDER BY
CONVERT(Date,CHINA_VISION_DorEvents.EventTM) DESC
This query doesn't currently attempt to work out the elapsed time, but here are the results of this so you can see how the data looks.
Ref CardCode EventTM
---------------------------------------
16 000006f1 2015-01-27 07:32:35.000
16 000006f1 2015-01-26 07:38:02.000
16 000006f1 2015-01-26 12:30:54.000
16 000006f1 2015-01-26 13:03:28.000
16 000006f1 2015-01-26 17:28:47.000
16 000006f1 2015-01-23 07:31:10.000
16 000006f1 2015-01-23 12:22:50.000
16 000006f1 2015-01-23 12:47:51.000
16 000006f1 2015-01-23 17:00:20.000
16 000006f1 2015-01-22 07:35:03.000
16 000006f1 2015-01-22 12:28:13.000
16 000006f1 2015-01-22 13:03:12.000
16 000006f1 2015-01-22 16:55:56.000
As you can see most days there are 4 records, and i need to work out the elapsed time for them so for example for the 26
07:38:02
12:30:54
elapsed time = 4 hours, 52 minutes and 52 seconds
13:03:28
17:28:47
Elapsed time = 4 hours, 25 minutes and 19 seconds
So the total elapsed for the 26th would be 9 hours 17 minuets 71
So in the result it would look like
Date Elapsed
2015-01-26 9:17:71
and so on
We do not need to calculate between 2-3 as the user is not logged on on here.
1 2 3 4
think of it like this ON - OFF BACK ON - OFF
table structure
Name type allow null
Reference int Unchecked
DorCtrls_Ref int Checked
EventsID tinyint Checked
EventTM datetime Checked
CardCode varchar(50) Checked
JustificationCode tinyint Checked
RecordIndex bigint Checked
Memo varchar(50) Checked
TempltCard varchar(1024)Checked
Templtlength varchar(32)Checked
TempltDir varchar(50) Checked
If you're not using a very old version of SQL Server, this will work for you:
Test Data:
CREATE TABLE Test(Ref int, CardCode varchar(20), EventTM datetime)
insert into Test
select 16,'000006f1','2015-01-27T07:32:35.000' union all
select 16,'000006f1','2015-01-26T07:38:02.000' union all
select 16,'000006f1','2015-01-26T12:30:54.000' union all
select 16,'000006f1','2015-01-26T13:03:28.000' union all
select 16,'000006f1','2015-01-26T17:28:47.000' union all
select 16,'000006f1','2015-01-23T07:31:10.000' union all
select 16,'000006f1','2015-01-23T12:22:50.000' union all
select 16,'000006f1','2015-01-23T12:47:51.000' union all
select 16,'000006f1','2015-01-23T17:00:20.000' union all
select 16,'000006f1','2015-01-22T07:35:03.000' union all
select 16,'000006f1','2015-01-22T12:28:13.000' union all
select 16,'000006f1','2015-01-22T13:03:12.000' union all
select 16,'000006f1','2015-01-22T16:55:56.000';
Query:
WITH ByDays AS ( -- Number the entry register in each day
SELECT
EventTm AS T,
CONVERT(VARCHAR(10),EventTm,102) AS Day,
FLOOR(CONVERT(FLOAT,EventTm)) DayNumber,
ROW_NUMBER() OVER(PARTITION BY FLOOR(CONVERT(FLOAT,EventTm)) ORDER BY EventTm) InDay
FROM Test
)
--SELECT * FROM ByDays ORDER BY T
,Diffs AS (
SELECT
E.Day,
E.T ET, O.T OT, O.T-E.T Diff,
DATEDIFF(S,E.T,O.T) DiffSeconds -- difference in seconds
FROM
(SELECT BE.T, BE.Day, BE.InDay
FROM ByDays BE
WHERE BE.InDay % 2 = 1) E -- Even rows
INNER JOIN
(SELECT BO.T, BO.Day, BO.InDay
FROM ByDays BO
WHERE BO.InDay % 2 = 0) O -- Odd rows
ON E.InDay + 1 = O.InDay -- Join rows (1,2), (3,4) and so on
AND E.Day = O.Day -- in the same day
)
--SELECT * FROM Diffs
SELECT Day,
SUM(DiffSeconds) Seconds,
CONVERT(VARCHAR(8),
(DATEADD(S, SUM(DiffSeconds), '1900-01-01T00:00:00')),
108) TotalHHMMSS -- The same, formatted as HH:MM:SS
FROM Diffs GROUP BY Day
The result looks like this.
Day Seconds TotalHHMMSS
2015.01.22 31554 08:45:54
2015.01.23 32649 09:04:09
2015.01.26 33491 09:18:11
See the corresponding sql fiddle: http://sqlfiddle.com/#!3/e1d31/1
From your result you have posted in your question, you can try the below code
CREATE TABLE #TEMP(Ref INT,CardCode VARCHAR(40),EventTM DATETIME)
INSERT INTO #TEMP
SELECT 16, '000006f1', '2015-01-27 07:32:35.000'
UNION ALL
SELECT 16, '000006f1', '2015-01-26 07:38:02.000'
UNION ALL
SELECT 16, '000006f1', '2015-01-26 12:30:54.000'
UNION ALL
SELECT 16, '000006f1', '2015-01-26 13:03:28.000'
UNION ALL
SELECT 16, '000006f1', '2015-01-26 17:28:47.000'
UNION ALL
SELECT 16, '000006f1', '2015-01-23 07:31:10.000'
UNION ALL
SELECT 16, '000006f1', '2015-01-23 12:22:50.000'
UNION ALL
SELECT 16, '000006f1', '2015-01-23 12:47:51.000'
UNION ALL
SELECT 16, '000006f1', '2015-01-23 17:00:20.000'
UNION ALL
SELECT 16, '000006f1', '2015-01-22 07:35:03.000'
UNION ALL
SELECT 16, '000006f1', '2015-01-22 12:28:13.000'
UNION ALL
SELECT 16, '000006f1', '2015-01-22 13:03:12.000'
UNION ALL
SELECT 16, '000006f1', '2015-01-22 16:55:56.000'
QUERY
;WITH CTE AS
(
-- Gets row number Order the date
SELECT ROW_NUMBER() OVER( ORDER BY EventTM)RNO, *
FROM #TEMP
)
,CTE2 AS
(
-- Split to hours,minutes and seconds
SELECT C1.*,C2.EventTM EM,DATEDIFF(S,C1.EventTM,C2.EventTM)DD,
cast(
(cast(cast(C2.EventTM as float) - cast(C1.EventTM as float) as int) * 24)
+ datepart(hh, C2.EventTM - C1.EventTM)
as INT)HH
,CAST(right('0' + cast(datepart(mi, C2.EventTM - C1.EventTM) as varchar(2)), 2)AS INT)MM
,CAST(right('0' + cast(datepart(ss, C2.EventTM - C1.EventTM) as varchar(2)), 2)AS INT)SS
FROM CTE C1
LEFT JOIN CTE C2 ON C1.RNO=C2.RNO-1
WHERE C1.RNO % 2 <> 0
),
CTE3 AS
(
-- Sum the hours, minute and seconds
SELECT CAST(EventTM AS DATE)EventTM,
SUM(HH) HH,SUM(MM) MM,SUM(SS) SS
FROM CTE2
GROUP BY CAST(EventTM AS DATE)
)
-- Format the elapsed time
SELECT EventTM,
CASE WHEN MM >=60 THEN CAST(HH+1 AS VARCHAR(10)) END + ':' +
CASE WHEN MM >=60 THEN right('0' + CAST(MM-60 AS VARCHAR(10)),2) END + ':' +
CAST(SS AS VARCHAR(10))Elapsed
FROM CTE3
EDIT :
From your query, you can use the below code
;WITH CTE AS
(
-- Gets row number Order the date
SELECT ROW_NUMBER() OVER( ORDER BY CONVERT(DateTime,CHINA_VISION_DorEvents.EventTM))RNO,
CHINA_VISION_DorEvents.DorCtrls_Ref Ref,
CHINA_VISION_PubCards.CardCode,
CONVERT(DateTime,CHINA_VISION_DorEvents.EventTM) EventTM
FROM CHINA_VISION_PubCards INNER JOIN
CHINA_VISION_DorEvents ON CHINA_VISION_PubCards.CardCode = CHINA_VISION_DorEvents.CardCode
WHERE (CHINA_VISION_PubCards.CardCode = '000006f1')
and CHINA_VISION_DorEvents.DorCtrls_Ref= '16'
)
,CTE2 AS
(
-- Split to hours,minutes and seconds
SELECT C1.*,C2.EventTM EM,DATEDIFF(S,C1.EventTM,C2.EventTM)DD,
cast(
(cast(cast(C2.EventTM as float) - cast(C1.EventTM as float) as int) * 24)
+ datepart(hh, C2.EventTM - C1.EventTM)
as INT)HH
,CAST(right('0' + cast(datepart(mi, C2.EventTM - C1.EventTM) as varchar(2)), 2)AS INT)MM
,CAST(right('0' + cast(datepart(ss, C2.EventTM - C1.EventTM) as varchar(2)), 2)AS INT)SS
FROM CTE C1
LEFT JOIN CTE C2 ON C1.RNO=C2.RNO-1
WHERE C1.RNO % 2 <> 0
),
CTE3 AS
(
-- Sum the hours, minute and seconds
SELECT CAST(EventTM AS DATE)EventTM,
SUM(HH) HH,SUM(MM) MM,SUM(SS) SS
FROM CTE2
GROUP BY CAST(EventTM AS DATE)
)
-- Format the elapsed time
SELECT EventTM,
CASE WHEN MM >=60 THEN CAST(HH+1 AS VARCHAR(10)) END + ':' +
CASE WHEN MM >=60 THEN right('0' + CAST(MM-60 AS VARCHAR(10)),2) END + ':' +
CAST(SS AS VARCHAR(10))Elapsed
FROM CTE3
Try this,The out put is correct .
your output is wrong.9:17:71 is wrong.it should be 9:18:11.
Declare @t table(Ref int, CardCode varchar(20), EventTM datetime)
insert into @t
select 16,'000006f1','2015-01-27 07:32:35.000' union all
select 16,' 000006f1','2015-01-26 07:38:02.000' union all
select 16,' 000006f1','2015-01-26 12:30:54.000' union all
select 16,' 000006f1','2015-01-26 13:03:28.000' union all
select 16,' 000006f1','2015-01-26 17:28:47.000' union all
select 16,' 000006f1','2015-01-23 07:31:10.000' union all
select 16,' 000006f1','2015-01-23 12:22:50.000' union all
select 16,' 000006f1','2015-01-23 12:47:51.000' union all
select 16,' 000006f1','2015-01-23 17:00:20.000' union all
select 16,' 000006f1','2015-01-22 07:35:03.000' union all
select 16,' 000006f1','2015-01-22 12:28:13.000' union all
select 16,' 000006f1','2015-01-22 13:03:12.000' union all
select 16,' 000006f1','2015-01-22 16:55:56.000'
;with CTE as
(
select *,row_number()over(partition by dateadd(d,0,datediff(d,0,EventTM))
order by EventTM)rn from @t
)
,CTE1 as
(
select Ref,CardCode,EventTM, rn oddrn,0 TimeElapse from CTE where rn%2<>0
union all
select a.Ref,a.CardCode,a.EventTM, rn ,datediff(s,b.EventTM,a.EventTM)
from CTE a
inner join CTE1 b on
dateadd(d,0,datediff(d,0,a.EventTM))= dateadd(d,0,datediff(d,0,b.EventTM))
and a.ref=b.ref
and a.rn-b.oddrn=1 and a.rn%2=0
)
select EventTM,cast((convert(varchar(5),TimeElapse/3600) +':'+
convert(varchar(5),TimeElapse%3600/60)
+':'+ convert(varchar(5),TimeElapse%60)) as datetime) from
(select dateadd(d,0,datediff(d,0,EventTM)) EventTM,sum(TimeElapse) TimeElapse
from cte1
where TimeElapse>0
group by dateadd(d,0,datediff(d,0,EventTM)))tbl
I haven't been able to test this myself but it may give you a good start. I would use a cursor if you want to keep it in SQL although I'd probably prefer to do it in CLR. Others may have a better method but you can try this:
Declare @olddate datetime,
@date datetime
DECLARE @Table table (Ref int, CardCode varchar(20), EventTM datetime, ElapsedTime varchar(30))
Declare cur_mycursor Cursor fast_forward for
SELECT CHINA_VISION_DorEvents.EventTM
FROM CHINA_VISION_PubCards INNER JOIN
CHINA_VISION_DorEvents ON CHINA_VISION_PubCards.CardCode = CHINA_VISION_DorEvents.CardCode
WHERE (CHINA_VISION_PubCards.CardCode = '000006f1')
and CHINA_VISION_DorEvents.DorCtrls_Ref= '16'
Order by CHINA_VISION_DorEvents.EventTM desc
Open cur_mycursor
Fetch next from cur_mycursor into @olddate
While @@FETCH_STATUS = 0
Begin
Fetch next from cur_mycursor into @date
INSERT INTO @Table (Ref, CardCode, EventTM, ElapsedTime)
SELECT CHINA_VISION_DorEvents.DorCtrls_Ref,
CHINA_VISION_PubCards.CardCode,
CHINA_VISION_DorEvents.EventTM,
case when Convert(varchar, @date, 112) = Convert(varchar, CHINA_VISION_DorEvents.EventTM, 112)
then Cast(datediff(mi, @date, CHINA_VISION_DorEvents.EventTM) / 1440 as varchar) + ' days ' +
Cast(datediff(mi, @date, CHINA_VISION_DorEvents.EventTM) % 1440 / 60 as varchar) + ' hours ' +
Cast(datediff(mi, @date, CHINA_VISION_DorEvents.EventTM) % 1440 %60 as varchar) + ' minutes'
else '0'
end as elapsedtime
FROM CHINA_VISION_PubCards INNER JOIN
CHINA_VISION_DorEvents ON CHINA_VISION_PubCards.CardCode = CHINA_VISION_DorEvents.CardCode
WHERE (CHINA_VISION_PubCards.CardCode = '000006f1')
and CHINA_VISION_DorEvents.DorCtrls_Ref= '16' and CHINA_VISION_DorEvents.EventTM = @olddate
Order by CHINA_VISION_DorEvents.EventTM desc
Set @olddate = @date
end
close cur_mycursor
Select * from @Table order by EventTM asc
deallocate cur_mycursor
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.