我正在创建一个查询,以获取某人在一天内完成的总小时数,但每天的时间可能有多次中断。
这是我目前的查询。
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
此查询当前不会尝试计算已用时间,但以下是此结果,以便您可以查看数据的外观。
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
正如你所看到的那样,大多数日子都有4条记录,我需要计算出它们的经过时间,例如对于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
所以26日的总时间是9小时17分钟71
所以在结果中它看起来像
Date Elapsed
2015-01-26 9:17:71
等等
我们无需在2-3之间进行计算,因为用户未在此处登录。
1 2 3 4
think of it like this ON - OFF BACK ON - OFF
表格结构
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
答案 0 :(得分:2)
如果您不使用非常旧版本的SQL Server,这将适用于您:
测试数据:
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';
查询:
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
结果如下所示。
Day Seconds TotalHHMMSS
2015.01.22 31554 08:45:54
2015.01.23 32649 09:04:09
2015.01.26 33491 09:18:11
查看相应的sql小提琴:http://sqlfiddle.com/#!3/e1d31/1
答案 1 :(得分:1)
根据您在问题中发布的结果,您可以尝试以下代码
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
编辑:
从您的查询中,您可以使用以下代码
;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
答案 2 :(得分:1)
试试这个,输出正确。
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
答案 3 :(得分:0)
我自己无法测试,但它可能会给你一个良好的开端。如果你想将它保存在SQL中,我会使用游标,尽管我可能更喜欢在CLR中执行它。其他人可能有更好的方法,但你可以试试这个:
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