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 am working on a SQL query where I have to select only one value of given time interval in seconds.
Suppose I give time interval=5, then the value should come after every 5 seconds. If I give time interval=60, then the value should come after every 60 seconds i.e. after every minute. If I give time interval=300, then the value should come after every 300 seconds i.e. after every 5 minutes and so on.
For this I used the following query
DECLARE #FROMDATETIME DATE = '2016-09-21 14:00',
#TODATETIME DATE = '2020-09-21 14:00',
#INTERVAL NVARCHAR(50) = '300'
DECLARE #intv INT = ((CONVERT(INT, #INTERVAL)) / 60)
SELECT
CONVERT(NVARCHAR(20), DATEANDTIME, 113) DATETIME,
ALARM, F870 'COLD JUICE PRE [PSI]',
F872 'COLD WATER PRE [PSI]', F82 'FILLER TEMP [DEGC]',
F810 'FLOW [LTR/MIN]', F869 'HOT JUICE PRE[PSI]',
F874 'HOT WATER PRE[PSI]', F867 'HOT WATER TEMP[DEGC]',
F84 'JUICE TEMP AFTER HOLD TUBE[DEGC]', F822 'PD FOR COLD PHE[PSI]',
F821 'PD FOR HOT PHE[PSI]', F8X 'PHE INLET TEMP[DEGC]',
B1 'MACHINE 1 STATUS', B2 'MACHINE 2 STATUS'
FROM
(SELECT
DATEANDTIME,
NULL ALARM, F870 F870, F872 F872, F82 F82, F810 F810, F869 F869,
F874 F874, F867 F867, F84 F84, F822 F822, F821 F821, F8X F8X,
CASE
WHEN B1 = 1 THEN 'ON'
ELSE 'OFF'
END B1,
CASE WHEN B2 = 1
THEN 'ON'
ELSE 'OFF'
END B2
FROM
DATALOGTABLE WITH (NOLOCK)
WHERE
(CONVERT(DATE, DATEANDTIME, 103) >= CONVERT(DATE, #FROMDATETIME, 103)
AND CONVERT(DATE, DATEANDTIME, 103) <= CONVERT(DATE, #TODATETIME, 103))
AND (((DATEPART(minute, dateandtime) % #intv) = 0))
UNION ALL
SELECT
DATEANDTIME, ALARMTXT ALARM,
NULL F870, NULL F872, NULL F82, NULL F810, NULL F869, NULL F874,
NULL F867, NULL F84, NULL F822, NULL F821, NULL F8X, NULL B1, NULL B2
FROM
DBO.ALARMHISTORY WITH (NOLOCK)
WHERE
(CONVERT(DATE, DATEANDTIME, 103) >= CONVERT(DATE, #FROMDATETIME, 103)
AND CONVERT(DATE, DATEANDTIME, 103) <= CONVERT(DATE, #TODATETIME, 103))
AND (((DATEPART(minute, dateandtime) % #intv) = 0))
) Z
ORDER BY
Z.DATEANDTIME DESC
In the above query I have given time interval of 300 second i.e. 5 minute means value should come after every 300 second or 5 minutes. But it is showing value of every minute.
09 Jan 2020 20:10:59 NULL 70.00 72.00 2.00 0.00 69.65
09 Jan 2020 20:10:58 NULL 70.00 72.00 2.00 0.00 69.65
09 Jan 2020 20:10:57 NULL 70.00 72.00 2.00 0.00 69.65
09 Jan 2020 20:10:56 NULL 70.00 72.00 2.00 0.00 69.65
09 Jan 2020 20:10:55 NULL 70.00 72.00 2.00 0.00 69.65
Here the first record have date '09 Jan 2020 20:10:59' and second should be
'09 Jan 2020 20:15:59' because interval given between two rows date is 300 seconds. which is not coming in this case. What to do here?
You seem try to mod minutes to seconds, you should correct this:
declare #DATETIME DATETIME = '2016-09-21 14:59:30';
declare #INTERVAL NVARCHAR(50) = '300'
select (DATEPART(minute, #DATETIME) * 60 + DATEPART(second, #DATETIME)) % #INTERVAL;
I'm using SQL server 2008 and don't know where to even begin this calculation. I would really appreciate any help you can provide.
I have two columns, StartTime and EndTime. I have three time ranges: morning 12:00 am - 7:59 am, day 8:00 am to 3:59 (or 15:39) pm, and evening 4:00 pm (or 16:00) to 11:59 (or 23:59) pm.
I want to calculate the number of hours between the StartTime and EndTime that belong in each range. For example, for the first row below, there are 11 hours between 6:00 and 17:00, and there are 2 hours in morning, 8 hours in day, and 1 hour in evening. So I want four columns: one for the 11 hours, one each for the morning, day and evening breakout.
StartTime EndTime
2017-10-25 06:00:00.000 2017-10-25 17:00:00.000
2017-10-26 05:30:00.000 2017-10-26 18:00:00.000
2017-10-30 07:00:00.000 2017-10-30 17:30:00.000
2017-11-01 06:00:00.000 2017-11-01 17:30:00.000
2017-10-06 04:00:00.000 2017-10-06 05:00:00.000
2016-04-28 04:00:00.000 2016-04-28 10:00:00.000
2017-06-30 04:00:00.000 2017-07-01 00:00:00.000
2016-01-26 06:30:00.000 2016-01-26 19:00:00.000
2017-08-15 07:00:00.000 2017-08-15 19:30:00.000
2016-01-28 07:00:00.000 2016-01-28 19:30:00.000
Desired results, using the first one
NbrHours = 11
MorningHrs = 2
DayHrs = 8
EveningHrs = 1
Something similar to this should do the trick for you ...
drop table if exists #times;
go
create table #times(
StartTime datetime ,
EndTime datetime
);
insert #times values
('2017-10-25 06:00:00.000', '2017-10-25 17:00:00.000'),
('2017-10-26 05:30:00.000', '2017-10-26 18:00:00.000'),
('2017-10-30 07:00:00.000', '2017-10-30 17:30:00.000'),
('2017-11-01 06:00:00.000', '2017-11-01 17:30:00.000'),
('2017-10-06 04:00:00.000', '2017-10-06 05:00:00.000'),
('2016-04-28 04:00:00.000', '2016-04-28 10:00:00.000'),
('2017-06-30 04:00:00.000', '2017-07-01 00:00:00.000'),
('2016-01-26 06:30:00.000', '2016-01-26 19:00:00.000'),
('2017-08-15 07:00:00.000', '2017-08-15 19:30:00.000'),
('2016-01-28 07:00:00.000', '2016-01-28 19:30:00.000')
;
with
a as (
select StartTime ,
EndTime ,
datepart(hour, StartTime) as StartHour ,
datepart(hour, StartTime) + datediff(hour, StartTime, EndTime) as EndHour
from #times
)
select a.StartTime,
a.EndTime ,
StartHour ,
EndHour ,
EndHour - StartHour as Total ,
case when EndHour > 8 then 8 else EndHour end - case when StartHour < 0 then 0 else StartHour end as Morning ,
case when EndHour > 16 then 16 else EndHour end - case when StartHour < 8 then 8 else StartHour end as Afternoon ,
case when EndHour > 24 then 24 else EndHour end - case when StartHour < 16 then 16 else StartHour end as Evening
from a
;