My goal is to check if an email is answered within 24 hours during workdays. de definition of a workday is if there is time registered in another table. this because we sometimes work on a Saturday or a Sunday or to exclude holidays. I made a view from that table that gives a 1 if the date has worktime or a 0 if there is no worktime registered.
DateWorked
HasWorked
2021-04-01 00:00:00.000
1
2021-04-02 00:00:00.000
1
2021-04-03 00:00:00.000
1
2021-04-04 00:00:00.000
0
2021-04-05 00:00:00.000
1
So for example a few situations:
1. MailIncoming: 2021-04-01 16:30:00, MailAnswering: 2021-04-02 14:00:00
This one is easy, I don't have to subtract anything and the mail is answered within 24 hours.
2. MailIncoming: 2021-04-01 09:30:00, MailAnswering: 2021-04-03 14:00:00
This one is also easy, I don't have to subtract anything and the mail is not answered within 24 hours.
3. MailIncoming: 2021-04-03 12:30:00, MailAnswering: 2021-04-05 10:00:00
There is 1 day where no one has worked, so I need to subtract 1 whole day from the total time, and in that case the email is answered within 24 hours during workdays.
4. MailIncoming: 2021-04-04 11:00:00, MailAnswering: 2021-04-05 18:00:00
The remaining 13 hours from 04 do not count toward the '24 hours during workdays' so the email is answered within 24 during workdays.
Also, there can be multiple dates with zero after each other.
So the outcome I'm looking for is:
MailIncoming
MailAnswering
TotalTime
TotalTimeWithoutDaysNotWorked
2021-04-04 11:00:00.000
2021-04-05 18:00:00.000
31
18
How can I calculate this last column? Or am I approaching this in the wrong way?
The query needs a way to generate calculated dates between MailIncoming and MailAnswering so there can be a LEFT JOIN (or INNER JOIN) to the WorkingDay table. In this case the query uses dbo.fnTally which is known to be a fast and efficient way to generate rows.
tables
drop table if exists #WorkingDay;
go
create table #WorkingDay(
DateWorked Date,
HasNotWorked int);
drop table if exists #MailIncoming;
go
create table #MailIncoming(
MailIncoming DateTime,
MailAnswering DateTime);
insert into #WorkingDay values
('2021-04-01', 0),
('2021-04-02', 0),
('2021-04-03', 0),
('2021-04-04', 1),
('2021-04-05', 0),
('2021-04-06', 0);
insert into #MailIncoming values
('2021-04-01 16:30:00', '2021-04-02 14:00:00'),
('2021-04-01 09:30:00', '2021-04-03 14:00:00'),
('2021-04-03 12:30:00', '2021-04-05 10:00:00'),
('2021-04-04 11:00:00', '2021-04-05 18:00:00');
dbo.fnTally
CREATE FUNCTION [dbo].[fnTally]
/**********************************************************************************************************************
Jeff Moden Script on SSC: https://www.sqlservercentral.com/scripts/create-a-tally-function-fntally
**********************************************************************************************************************/
(#ZeroOrOne BIT, #MaxN BIGINT)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN WITH
H2(N) AS ( SELECT 1
FROM (VALUES
(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
)V(N)) --16^2 or 256 rows
, H4(N) AS (SELECT 1 FROM H2 a, H2 b) --16^4 or 65,536 rows
, H8(N) AS (SELECT 1 FROM H4 a, H4 b) --16^8 or 4,294,967,296 rows
SELECT N = 0 WHERE #ZeroOrOne = 0 UNION ALL
SELECT TOP(#MaxN)
N = ROW_NUMBER() OVER (ORDER BY N)
FROM H8
;
query
select mi.MailIncoming, mi.MailAnswering,
avg(datediff(hour, MailIncoming, MailAnswering)) hrs_to_ans,
sum(case when w.HasNotWorked=1 and
v.calc_dt > mi_dt.inc_dt and
v.calc_dt < mi_dt.ans_dt
then -24
when w.HasNotWorked=1
then datediff(hour, dateadd(day, 1, mi_dt.inc_dt), mi.MailIncoming)
else 0 end) hrs_to_sub
from #MailIncoming mi
cross apply (values (cast(MailIncoming as date),
cast(MailAnswering as date))) mi_dt(inc_dt, ans_dt)
cross apply dbo.fnTally(0, datediff(day, mi.MailIncoming, mi.MailAnswering)) fn
cross apply (values (dateadd(day, fn.n, mi_dt.inc_dt))) v(calc_dt)
left join #WorkingDay w on v.calc_dt=w.DateWorked
group by mi.MailIncoming, mi.MailAnswering
order by mi.MailIncoming;
MailIncoming MailAnswering hrs_to_ans hrs_to_sub
2021-04-01 09:30:00.000 2021-04-03 14:00:00.000 53 0
2021-04-01 16:30:00.000 2021-04-02 14:00:00.000 22 0
2021-04-03 12:30:00.000 2021-04-05 10:00:00.000 46 -24
2021-04-04 11:00:00.000 2021-04-05 18:00:00.000 31 -13
I suggest you to use a column HasNotWorked, so the tables are
create table WorkingDay(DateWorked Date, HasNotWorked int);
create table MailIncoming(MailIncoming DateTime, MailAnswering DateTime);
and the rows
insert into WorkingDay values('2021-04-01', 0);
insert into WorkingDay values('2021-04-02', 0);
insert into WorkingDay values('2021-04-03', 0);
insert into WorkingDay values('2021-04-04', 1);
insert into WorkingDay values('2021-04-05', 0);
insert into WorkingDay values('2021-04-06', 0);
insert into MailIncoming values('2021-04-04 11:00:00.000', '2021-04-06 18:00:00.000');
I want calculate the start date. If is in working day, we must consider the hour of the mail, else the first working day with
case when
(select HasNotWorked from WorkingDay where DateWorked = convert(date, MailIncoming)) = 1 then
(select min(DateWorked) from WorkingDay where DateWorked > MailIncoming and HasNotWorked = 0)
else MailIncoming end as startDate
and discard the day that are not working day
((select sum(HasNotWorked) from WorkingDay where DateWorked between convert(date, startDate)
and convert(date, MailAnswering)
) * 24) as numNotWorkingDay
so the query could be
select startDate, MailAnswering, MailIncoming, hour, numNotWorkingDay, hour - numNotWorkingDay hourWitoutWorkingDay
from (
select
MailAnswering, startDate, MailIncoming,
DateDiff("hh", startDate, MailAnswering) hour,
((select sum(HasNotWorked) from WorkingDay where DateWorked between convert(date, startDate)
and convert(date, MailAnswering)
) * 24) as numNotWorkingDay
from (
select *,
case when
(select HasNotWorked from WorkingDay where DateWorked = convert(date, MailIncoming)) = 1 then
(select min(DateWorked) from WorkingDay where DateWorked > MailIncoming and HasNotWorked = 0)
else MailIncoming end as startDate
from MailIncoming) as startCalc
) as calcTable;
sqlfiddle
i have this ms-sql code below, running on sql server 2017:
DECLARE #report_int TABLE
(
atimestamp DATETIME,
adate DATE,
ahour INT,
intvalue INT,
attribute CHAR(254),
total INT
)
INSERT INTO #report_int
SELECT
el.servertimestamp,
cast(el.servertimestamp as date) adate,
(DATEPART(HH,el.servertimestamp)) ahour,
el.intvalue,
el.attributes,
0
FROM
eventlog el
where
el.servertimestamp BETWEEN '6/29/2017'
AND DATEADD(dd, +1, '6/29/2019')
and (attributes LIKE '%N<=>OlympieioIn%' OR attributes LIKE '%N<=>OlympieioOut%')
order by
el.servertimestamp
DECLARE #report TABLE
(
adate datetime,
ahour int,
came_in bigint,
gone_out bigint
)
--fill report with dates and hours
INSERT INTO #report (adate, ahour) SELECT DISTINCT adate, ahour FROM #report_int
--reset
UPDATE #report set came_in = 0, gone_out = 0
--update in totals, min and max times
UPDATE #report SET came_in = i.total from
#report r,
(
select adate, ahour, COUNT(*) total
FROM #report_int
WHERE attribute LIKE 'N<=>OlympieioIn'
GROUP BY adate, ahour
) i
WHERE
i.adate = r.adate
and i.ahour = r.ahour
--update out totals
UPDATE #report SET gone_out = i.total from
#report r,
(
SELECT adate, ahour, COUNT(*) total
FROM #report_int
WHERE attribute LIKE 'N<=>OlympieioOut'
GROUP BY adate, ahour
) i
where
i.adate = r.adate
and i.ahour = r.ahour
select
adate,
ahour,
RIGHT('00'+cast(ahour as varchar),2)+':00 - '+RIGHT('00'+cast(ahour+1 as varchar),2)+':00' timeframe,
came_in,
gone_out
from
#report
This code shows how many people came in or gone out of a building every day. As you can see, the amount of people who come in and go out, are displayed in an hourly grouping.
Below is a screenshot of the executed code.
What i want to do is group these data in a 2-hour grouping.For example, the grouping of the 3rd and 4th hour of the executed code above, will be:
DATE(adate): 2018-05-12
Hour(ahour): 15
Timeframe: 15:00-17:00
came_in: 0
gone_out: 2
Your help will be much appreciated,
thank you.
One way to get a datetime to the last 2 hour slot would be to use:
DATEADD(HOUR, DATEDIFF(HOUR, 0, YourDateColumn) - (DATEDIFF(HOUR, 0, YourDateColumn) % 2), 0)
If we then take some (random) sample data, you get the following:
WITH VTE AS (
SELECT CONVERT(datetime2(0),V.DT) AS DT
FROM (VALUES('2018-07-04T00:11:32'),('2018-07-04T01:17:12'),('2018-07-04T02:00:01'),('2018-07-04T07:49:59'),('2018-07-04T07:59:58'),('2018-07-04T08:00:00')) V(DT))
SELECT DT, DATEADD(HOUR, DATEDIFF(HOUR, 0, DT) - (DATEDIFF(HOUR, 0, DT) % 2), 0) AS DT2h
FROM VTE;
Which returns:
DT DT2h
--------------------------- -----------------------
2018-07-04 00:11:32 2018-07-04 00:00:00.000
2018-07-04 01:17:12 2018-07-04 00:00:00.000
2018-07-04 02:00:01 2018-07-04 02:00:00.000
2018-07-04 07:49:59 2018-07-04 06:00:00.000
2018-07-04 07:59:58 2018-07-04 06:00:00.000
2018-07-04 08:00:00 2018-07-04 08:00:00.000
If you wanted a COUNT by 2 hour slot:
WITH VTE AS (
SELECT CONVERT(datetime2(0),V.DT) AS DT
FROM (VALUES('2018-07-04T00:11:32'),('2018-07-04T01:17:12'),('2018-07-04T02:00:01'),('2018-07-04T07:49:59'),('2018-07-04T07:59:58'),('2018-07-04T08:00:00')) V(DT))
SELECT DATEADD(HOUR, DATEDIFF(HOUR, 0, DT) - (DATEDIFF(HOUR, 0, DT) % 2), 0) AS DT2h, COUNT(DT) AS C
FROM VTE
GROUP BY DATEADD(HOUR, DATEDIFF(HOUR, 0, DT) - (DATEDIFF(HOUR, 0, DT) % 2), 0);
Which returns:
DT2h C
----------------------- -----------
2018-07-04 00:00:00.000 2
2018-07-04 02:00:00.000 1
2018-07-04 06:00:00.000 2
2018-07-04 08:00:00.000 1
I would simply manually create a timetable and join it.
The timetable would have 24 rows (one for each hour) and could look like this:
hour hourtimeframe twohourtimeframe
13 13:00 - 14:00 13:00 - 15:00
Joined just to ask this because it is killing me :) Great forum with a lot of great minds!
I simply need to join these two tables, i can only join them on date and time no other columns are available.
Table 1 has for example following columns
Film -----------------Datetime……………………………Duration(minutes)
TITANIC------------2016-01-01 01:00:00-----------------60
Armageddon---------2016-01-01 02:00:00-----------------60
Table 2 has following columns
Date----------------Time
2016-01-01……….01:00:00
2016-01-01……….01:01:00
2016-01-01……….01:02:00
2016-01-01……….01:03:00
…and so on
Table 2 contains info for every minute but table one only one specific time and date per event. so i need to match for every minute in table two with what i got from table one.
Any ideas? i'll take anything that works :) btw sorry for the formatting!
Edit:
Desired result would be something like
TITANIC------------2016-01-01 01:00:00-----------------60
TITANIC------------2016-01-01 01:01:00-----------------60
TITANIC------------2016-01-01 01:02:00-----------------60
Armageddon---------2016-01-01 02:00:00-----------------60
Armageddon---------2016-01-01 02:01:00-----------------60
Armageddon---------2016-01-01 02:02:00-----------------60
And so on...
convert the table 2 date and time to a datetime and see if it is between table 1 datetime and datetime + duration.
SELECT *
FROM table1 t1
JOIN table2 t2 ON CAST(t2.Date AS DATETIME)
+ CAST(t2.Time AS DATETIME) >= t1.Datetime
AND CAST(t2.Date AS DATETIME)
+ CAST(t2.Time AS DATETIME) < DATEADD(MIN,
t1.Duration,
t1.Datetime)
I'm going to make some assumptions as you haven't outlined the table structure.
Your film table is of the following structure:
CREATE TABLE Films ([Film] NVARCHAR(128), [DateTime] DATETIME, Duration INT)
GO
Your Date/Time values table is of the following structure:
CREATE TABLE DateTimeValues ([Date] DATE, [Time] TIME)
GO
Lets insert your values:
--Insert Values for Films
INSERT INTO Films
VALUES ('TITANIC', '2016-01-01T01:00:00', 60),
('Armageddon', '2016-01-01 02:00:00', 60)
GO
--Insert Values for every minute of 2016-01-01
DECLARE #DATETIMEBEGIN DATETIME
SET #DATETIMEBEGIN = '2016-01-01'
DECLARE #DATETIMEEND DATETIME
SELECT #DATETIMEEND = '2016-01-02'
;WITH CTE AS (SELECT DATEADD(day, 0, DATEDIFF(day, 0, #DATETIMEBEGIN)) DateTimeValues
UNION ALL
SELECT DATEADD(MINUTE, 1, DateTimeValues) AS DateTimeValues
FROM CTE
WHERE DateTimeValues < #DATETIMEEND
)
INSERT INTO DateTimeValues
SELECT CONVERT(DATE, DateTimeValues) "Date",
CONVERT(TIME, DateTimeValues) "Time"
FROM CTE
OPTION (MAXRECURSION 0)
GO
Lets make it simple and lets caluclate the start time/end time for each film according to the duration. The query you will need for your desired output is:
;WITH CTEFilms AS
(
SELECT Film,
CONVERT(DATE, [DateTime]) "Date",
CONVERT(TIME, [DateTime]) "StartTime",
CONVERT(TIME, DATEADD(MINUTE,Duration,[DateTime])) "EndTime",
Duration
FROM Films
)
SELECT f.Film,
CAST(dtv."Date" AS DATETIME) + dtv."Time" "DateTime",
Duration
FROM CTEFilms f
INNER JOIN DateTimeValues dtv
ON f.[Date] = dtv.[Date]
AND dtv.[Time] >= f.StartTime
AND dtv.[Time] < f.EndTime
ORDER BY Film, Time
Your Results:
Film DateTime Duration
Armageddon 2016-01-01 02:00:00.000 60
Armageddon 2016-01-01 02:01:00.000 60
Armageddon 2016-01-01 02:02:00.000 60
Armageddon 2016-01-01 02:03:00.000 60
Armageddon 2016-01-01 02:04:00.000 60
...
Armageddon 2016-01-01 02:55:00.000 60
Armageddon 2016-01-01 02:56:00.000 60
Armageddon 2016-01-01 02:57:00.000 60
Armageddon 2016-01-01 02:58:00.000 60
Armageddon 2016-01-01 02:59:00.000 60
TITANIC 2016-01-01 01:00:00.000 60
TITANIC 2016-01-01 01:01:00.000 60
TITANIC 2016-01-01 01:02:00.000 60
TITANIC 2016-01-01 01:03:00.000 60
TITANIC 2016-01-01 01:04:00.000 60
...
TITANIC 2016-01-01 01:55:00.000 60
TITANIC 2016-01-01 01:56:00.000 60
TITANIC 2016-01-01 01:57:00.000 60
TITANIC 2016-01-01 01:58:00.000 60
TITANIC 2016-01-01 01:59:00.000 60
#Eddie B, you did not give out your table structure, i.e. column data types, so I just come up with the following assumed code/data
use tempdb
drop table dbo.t1, dbo.t2;
create table dbo.T1 (film varchar(10), dt datetime, duration int)
create table dbo.T2 (dt varchar(10), tm varchar(10));
go
-- populate the tables with SOME sample data
insert into dbo.T1(film, dt, duration)
values ('Titanic', '2016-01-01 01:00:00', 5), ('Amageddon', '2016-01-01 02:00:00', 4)
insert into dbo.T2 (dt, tm)
values
('2016-01-01', '01:00:00')
, ('2016-01-01', '01:01:00')
, ('2016-01-01', '01:02:00')
, ('2016-01-01', '01:03:00')
, ('2016-01-01', '01:04:00')
, ('2016-01-01', '01:05:00')
, ('2016-01-01', '02:00:00')
, ('2016-01-01', '02:01:00')
, ('2016-01-01', '02:02:00')
, ('2016-01-01', '02:03:00')
, ('2016-01-01', '02:04:00')
, ('2016-01-01', '02:05:00')
, ('2016-01-01', '03:00:00');
go
-- here is the result
select t1.film, [DateTime]= convert(datetime, t2.dt + ' ' + t2.tm), t1.duration
from dbo.t1
inner join dbo.t2
on convert(datetime, t2.dt + ' ' + t2.tm) >= t1.dt
and convert(datetime, t2.dt + ' ' + t2.tm) <= dateadd(minute, t1.duration, t1.dt)
go
Here is the result:
Please how may we do this:
1) Generate 24 rows one for each hour from current time back 24 hours
2) Aggregate data from another table over the past 24 hours into these 24 data points.
I have seen solutions suggesting number tables from 0-23, but these might make it difficult if we need this to start from NOW, then run back 24 hours Get every hour for a time range
e.g [5:00am, 4:00am, 3:00am ... 12:am, 11pm ... 7:00am,6:00am]
Source Table:
select d,h,count(1)cnt from msgs
where dt>= DateAdd(hh, -24, sysdatetime())
group by d,h order by 1 desc,2 desc
Sample Data
d h cnt
2015-06-05 16 11
2015-06-05 13 44
2015-06-05 12 16
2015-06-05 11 31
2015-06-05 10 10
2015-06-05 9 12
2015-06-05 8 1
2015-06-04 21 1
2015-06-04 20 2
2015-06-04 18 5
2015-06-04 16 2
I have missing hours, i would need a query that fills out the missing hours with 0
As an alternative solution, you could use this query to provide all 24 hour ranges. Then simply aggregate and sum these values against your original query to return only 24 rows.
;WITH hrs AS
(
SELECT h = 1
UNION ALL
SELECT h + 1
FROM hrs
WHERE h + 1 <= 24
)
SELECT
d = left(convert(varchar(50),DateAdd(hour, -1 * h, getdate()), 21),10),
h = DatePart(hour, DateAdd(hour, -1 * h, getdate())),
cnt = 0
FROM hrs
You could try joining to this function:
CREATE FUNCTION ufn_Last24Hrs
(
#start DateTime2(7)
)
RETURNS #Result TABLE (d char(10), h int)
AS
BEGIN
DECLARE #current DateTime2(7) = #start
WHILE (#current > DateAdd(hour, -24, #start))
BEGIN
INSERT INTO #Result
VALUES
(
REPLACE(CONVERT(char(10), #current, 102) , '.', '-'),
DATEPART(hour, #current)
)
SET #current = DateAdd(hour, -1, #current)
END
RETURN;
END;
GO
SELECT * FROM ufn_Last24Hrs(SYSDATETIME());
SELECT
d,h,COUNT(1)cnt
FROM
ufn_Last24Hrs(SYSDATETIME()) hrs
left join msgs
ON msgs.d = hrs.d
and msgs.h = hrs.h
WHERE dt>= DateAdd(hour, -24, SYSDATETIME())
GROUP BY d,h
ORDER BY 1 DESC, 2 DES
I have this table in SQL Server:
UserId Date Start Time End Time
------------------------------------------------------------------------------------
20 2012-04-02 00:00:00.000 NULL 2012-04-02 09:17:57.000
20 2012-04-02 00:00:00.000 2012-04-02 09:17:57.000 2012-04-02 09:57:55.000
20 2012-04-02 00:00:00.000 2012-04-02 09:57:55.000 2012-04-02 10:04:58.000
20 2012-04-02 00:00:00.000 2012-04-02 10:04:58.000 2012-04-02 10:21:40.000
20 2012-04-02 00:00:00.000 2012-04-02 10:22:15.000 2012-04-02 10:22:20.000
20 2012-04-02 00:00:00.000 2012-04-02 10:22:56.000 2012-04-02 10:23:33.000
I want to find the difference between start time and end time and sum up the difference hours based on date
Output required is:
UserID Time_Duration
-----------------------
20 1:20:20 (this is example not actuals)
Can anyone help me write a SQL query..
I have tried with the below query,
select sum(sub1.TotalSeconds / 3600) as [Hours], sum((sub1.TotalSeconds % 3600) / 60)
as [Minutes],
sum((sub1.TotalSeconds % 3600) % 60) as [Seconds],sub1.Date
from
(
SELECT
sub.UserID,
sub.Date,
sum(datepart(hour, sub.end_time-sub.start_time) * 3600) + sum(datepart(minute, sub.end_time-sub.start_time) * 60) +
sum(datepart(second, sub.end_time-sub.start_time)) as TotalSeconds
from.......
) AS sub
group by sub.UserID,sub.Date,sub.start_time,sub.end_time)
as sub1 group by sub1.Date;
I get the following result
Hours Minutes Seconds Date
3 347 515 2012-04-02 00:00:00.000
But i want to add the minutes if greater then 60 it has to hours as 3+1 hr and so on. Can any 1 help me where Im making mistake
Hi take a look at this:
SQLFIDDLE
It is NOT the most efficient and I believe it's ugly for a code. However put it across for you to see the steps. You may get an idea out of it. Mainly using arimethic operators to get the reusults. There are extra fields as I was using it mainly to show you the data flow. I am sure other approaches are much much efficient in terms of performance. You can try.
Query:
select q.userid, t.date,
q.h + round((q.m + (q.s/60))/60,0) as hh,
round((q.m + (q.s/60)) mod 60,0) as mm,
q.s mod 60 as ss
from
(select t.userid,t.date,
sum(t.hours) as h,
sum(t.minutes) as m,
sum(t.seconds) as s
from (select userid,date,
TIMEDIFF(EndTime, StartTime) as duration,
TIMESTAMPDIFF(hour,starttime,endtime) as hours,
TIMESTAMPDIFF(minute,starttime,endtime) mod 60 as minutes,
TIMESTAMPDIFF(second,starttime,endtime) mod 60 seconds
from datestimes) as t
) as q
;
Resutls
USERID DATE HH MM SS
20 April, 02 2012 00:00:00+0000 13 4 25
Updated Query only with one nested query
Infact you may achieve this with one nested query. Apology as this whole answer is MYSQL based. So hopefully you may take the logic out to implement that using SQL Server syntax :)
select t.userid, t.date,
(sum(t.hours) + round((sum(t.minutes) +
sum(t.seconds)/60)/60,0)) as h,
(round((sum(t.minutes) +
sum(t.seconds)/60) mod 60,0)) as m,
sum(t.seconds) mod 60 as s
from
(select userid, date,
TIMEDIFF(EndTime, StartTime) as duration,
TIMESTAMPDIFF(hour,starttime,endtime) as hours,
TIMESTAMPDIFF(minute,starttime,endtime) mod 60 as minutes,
TIMESTAMPDIFF(second,starttime,endtime) mod 60 seconds
from datestimes) as t
;
You can do this matematically:
Select
CAST(DATEDIFF(SECOND, StartDate, EndDate) / 3600 as VARCHAR) + ':' +
CAST((DATEDIFF(SECOND, StartDate, EndDate) % 3600) / 60 as VARCHAR) + ':' +
CAST(DATEDIFF(SECOND, StartDate, EndDate) % 60 as VARCHAR) as DateDifference
From YourTable
DATEDIFF function gives you difference in seconds between start and end time as integer value. Simple dividing that value with 3600, or 60, you've got hours, or minutes, and with % you've got remain values.
Declare #test table(start datetime,ende datetime)
insert into #test Values ('20120101 10:00','20120101 18:00')
insert into #test Values ('20120101 10:00','20120101 18:13')
insert into #test Values ('20120101 10:00','20120102 18:25')
insert into #test Values ('20120101 10:00','20120101 18:00')
insert into #test Values ('20120101 10:00','20120101 18:00')
Select
FLOOR(Cast(Dummy as Float)) as Days
,DATEPART(Hour,dummy) as Hours
,DATEPART(MINUTE,dummy) as Minutes
,DATEPART(Second,dummy) as Seconds
from
(
Select
DateAdd(second, SUM(DATEDIFF(SECOND,start,ende)),Cast(0 as Datetime)) as Dummy
from #test
) a