I need to calculate the call waiting time (Hold time) during an interval of 30 minutes
HoldTime is given in seconds
Input Data
| Date | ID |StartDate | StartTime |holdtime |
--------- ------- ---------- -------------------- ---------
28/12/2022 3110522 28/12/2022 10:03:46.0000000 62
28/12/2022 3110522 28/12/2022 10:36:42.0000000 189
28/12/2022 3110522 28/12/2022 11:06:54.0000000 65
28/12/2022 3110522 28/12/2022 11:11:46.0000000 79
28/12/2022 3110522 28/12/2022 11:19:55.0000000 118
28/12/2022 3110522 28/12/2022 11:38:20.0000000 36
28/12/2022 3110522 28/12/2022 12:13:46.0000000 67
28/12/2022 3110522 28/12/2022 13:45:27.0000000 24
28/12/2022 3110522 28/12/2022 13:52:59.0000000 144
28/12/2022 3110522 28/12/2022 15:02:43.0000000 39
28/12/2022 3110522 28/12/2022 16:00:41.0000000 246
28/12/2022 3110522 28/12/2022 16:54:22.0000000 79
28/12/2022 3110522 28/12/2022 16:59:18.0000000 94
28/12/2022 3110522 28/12/2022 17:29:19.0000000 84
28/12/2022 3110522 28/12/2022 17:54:44.0000000 64
Output Data
|ID | StartDate |intervalStartTime | intervalStoptTime | holdtime
------ --------- ----------------- ------------------- ----------
3110522 28/12/2022 10:00:00.000 10:30:00.0000000 62
3110522 28/12/2022 10:30:00.000 11:00:00.0000000 189
3110522 28/12/2022 11:00:00.000 11:30:00.0000000 262
3110522 28/12/2022 11:30:00.000 12:00:00.0000000 36
3110522 28/12/2022 12:00:00.000 12:30:00.0000000 67
3110522 28/12/2022 13:30:00.000 14:00:00.0000000 168
3110522 28/12/2022 15:00:00.000 15:30:00.0000000 39
3110522 28/12/2022 16:00:00.000 16:30:00.0000000 246
3110522 28/12/2022 16:30:00.000 17:00:00.0000000 121
3110522 28/12/2022 17:00:00.000 17:30:00.0000000 93
3110522 28/12/2022 17:30:00.000 18:00:00.0000000 107
I am making a function to split data, however I am not getting what I want. I think I'm doing something too complicated to solve it. Using a loop like WHILE is not something I like to use in SQL.
while (#eventDurationMins>0)
begin
set #eventDurationInIntervalMins = cast(#intervalEndTime-#eventStartTime as float)*24*60 ;
if #eventDurationMins<#eventDurationInIntervalMins
set #eventDurationInIntervalMins = #eventDurationMins ;
insert into #retTable
select #intervalStartTime,#intervalEndTime,#eventDurationInIntervalMins
set #eventDurationMins = #eventDurationMins - #eventDurationInIntervalMins ;
set #eventStartTime = #intervalEndTime;
set #intervalStartTime = #intervalEndTime;
set #intervalEndTime = dateadd(minute,#intervalMins,#intervalEndTime);
end;
Thanks in advance,
They key here is to find the timeslot in 30 minutes. The TimeSlot computation is basically to "round down" the time to every 30 minutes. Example : from 10:00 to 10:29 round down to 10:00 etc
select ID, StartDate,
intervalStartTime = TimeSlot,
intervalStoptTime = dateadd(minute, 30, TimeSlot),
holdtime = sum(holdtime)
from
(
select *,
TimeSlot = convert(time(0),
dateadd(second,
convert(int,
datediff(second, '00:00:00', StartTime)
/ 30.0 / 60.0) * 30 * 60, '00:00'))
from InputData
) i
group by ID, StartDate, TimeSlot
Edit :
CTE numbers is just a tally table. It is used to explode those rows where the holdTime span across multiple time slot
The holdtime (ht) is calculated in below case expression. First condition is where the hold time contains within same time slot. The remaining 3 conditions are to handle when the explode case
ht = case when n = 0
and count(*) over(partition by [Date], [ID], [StartDate], [StartTime]) = 1
then holdTime
when n = 0
then datediff(second, StartTime, dateadd(minute, 30, TimeSlot))
when n = count(*) over(partition by [Date], [ID], [StartDate], [StartTime]) - 1
then datediff(second, dateadd(minute, n * 30, TimeSlot), EndTime)
else 30 * 60
end
The query
with
numbers as
(
select n = 0
union all
select n = n + 1
from numbers
where n < 99
),
cte as
(
select *
from InputData i
cross apply
(
select EndTime = dateadd(second, holdTime, StartTime),
TimeSlot = convert(time(0),
dateadd(second,
convert(int,
datediff(second, '00:00:00', StartTime)
/ 30.0 / 60.0) * 30 * 60, '00:00'))
) t
cross apply
(
select EndTimeSlot = convert(time(0),
dateadd(second,
convert(int,
datediff(second, '00:00:00', EndTime)
/ 30.0 / 60.0) * 30 * 60, '00:00'))
) e
),
cte2 as
(
select [Date], [ID], [StartDate], [StartTime], [EndTime],
TimeSlot = dateadd(minute, n * 30, TimeSlot),
ht = case when n = 0
and count(*) over(partition by [Date], [ID], [StartDate], [StartTime]) = 1
then holdTime
when n = 0
then datediff(second, StartTime, dateadd(minute, 30, TimeSlot))
when n = count(*) over(partition by [Date], [ID], [StartDate], [StartTime]) - 1
then datediff(second, dateadd(minute, n * 30, TimeSlot), EndTime)
else 30 * 60
end
from cte i
inner join numbers n
on n.n >= 0
and n.n <= datediff(minute, TimeSlot, EndTimeSlot) / 30
)
select ID, StartDate,
intervalStartTime = TimeSlot,
intervalStoptTime = dateadd(minute, 30, TimeSlot),
holdtime = sum(ht)
from cte2
group by ID, StartDate, TimeSlot
order by intervalStartTime
db<>fiddle demo
Related
This has been driving me crazy, any help is much appreciated. Code and results below - my question is simple. On the results line 4, the Activity does NOT match lag_Activity, why does the group number not increase?
create table #exampleTable
(name varchar(20)
,pnum bigint
,activity varchar(10)
,startTime datetime
,endTime datetime)
insert into #exampleTable
values
('Harry Potter',12345678, 'On Shift', '2022-05-18 13:00:00', '2022-05-18 22:00:00')
,('Harry Potter',12345678,'Off Shift','2022-05-18 16:30:00','2022-05-18 17:30:00')
,('Jane Doe',98765432,'Off Shift','2022-05-18 02:00:00','2022-05-18 05:00:00')
,('Jane Doe',98765432,'On Shift','2022-05-18 02:00:00','2022-05-18 16:00:00')
,('Jane Doe',98765432,'Off Shift','2022-05-18 06:15:00','2022-05-18 06:45:00')
,('Jane Doe',98765432,'Off Shift','2022-05-18 11:30:00','2022-05-18 12:00:00')
,('Jane Doe',98765432,'Off Shift','2022-05-18 12:00:00','2022-05-18 15:50:00')
select
sum(case when activity = lag_activity and starttime <= lag_endtime then 0 else 1 end) over(partition by pnum order by pnum, starttime) as grp
,*
from (
select
*
,lag(endtime) over(order by pnum, starttime) lag_endtime
,lag(activity) over(order by pnum, starttime) lag_activity
from #exampleTable
where endtime-Starttime>0
) a
order by pnum, starttime
Here are the results:
grp name pnum activity lag_activity startTime endTime lag_endtime
1 Harry Potter 12345678 On Shift NULL 2022-05-18 13:00:00.000 2022-05-18 22:00:00.000 NULL
2 Harry Potter 12345678 Off Shift On Shift 2022-05-18 16:30:00.000 2022-05-18 17:30:00.000 2022-05-18 22:00:00.000
1 Jane Doe 98765432 Off Shift Off Shift 2022-05-18 02:00:00.000 2022-05-18 05:00:00.000 2022-05-18 17:30:00.000
1 Jane Doe 98765432 On Shift Off Shift 2022-05-18 02:00:00.000 2022-05-18 16:00:00.000 2022-05-18 05:00:00.000
2 Jane Doe 98765432 Off Shift On Shift 2022-05-18 06:15:00.000 2022-05-18 06:45:00.000 2022-05-18 16:00:00.000
3 Jane Doe 98765432 Off Shift Off Shift 2022-05-18 11:30:00.000 2022-05-18 12:00:00.000 2022-05-18 06:45:00.000
3 Jane Doe 98765432 Off Shift Off Shift 2022-05-18 12:00:00.000 2022-05-18 15:50:00.000 2022-05-18 12:00:00.000
Thanks to #ConorCunninghamMSFT for the tip, the lag functions and Sum Over function needed additional ordering. The order itself is less important than the fact that it stays consistent.
select
sum(case when activity = lag_activity and starttime <= lag_endtime then 0 else 1 end) over(partition by pnum order by pnum, starttime, endtime) as grp
,*
from (
select
*
,lag(endtime) over(order by pnum, starttime, endtime) lag_endtime
,lag(activity) over(order by pnum, starttime, endtime) lag_activity
from #exampleTable
where endtime-Starttime>0
) a
order by pnum, starttime, endtime
I have a table tbl_attendance in SQL Server with data is in this format
card_no adate time
-----------------------------------------
13 2016-08-01 2016-08-01 09:30:00
13 2016-08-01 2016-08-01 11:00:00
13 2016-08-01 2016-08-01 12:00:00
13 2016-08-01 2016-08-01 15:00:00
13 2016-08-01 2016-08-01 16:00:00
13 2016-08-02 2016-08-02 09:30:00
but when I execute my query, I want to get results in this format
card_no adate time_in time_in
----------------------------------------------------------------
13 2016-08-01 2016-08-01 09:30:00 2016-08-01 11:00:00
13 2016-08-01 2016-08-01 12:00:00 2016-08-01 15:00:00
13 2016-08-01 2016-08-01 16:00:00 null
13 2016-08-02 2016-08-02 09:30:00 null
Please help as soon as possible
Try this trick
;WITH cte
AS (SELECT *,
((Row_number()OVER(partition BY [adate] ORDER BY [time])-1)%2) + 1 AS seq_no,
((Row_number()OVER(partition BY [adate] ORDER BY [time])-1)/2) + 1 rang_no
FROM Yourtable)
SELECT [card_no],
[adate],
time_in = Min(CASE WHEN seq_no = 1 THEN [time] END),
time_in = Min(CASE WHEN seq_no = 2 THEN [time] END)
FROM cte
GROUP BY [card_no],
[adate],
rang_no
Demo
Schema Setup
IF Object_id('tempdb.dbo.#Table1') is not null
DROP TABLE #Table1
CREATE TABLE #Table1
([card_no] int, [adate] date, [time] datetime);
Sample Data
INSERT INTO #Table1
([card_no], [adate], [time])
VALUES
(13, '2016-08-01 00:00:00', '2016-08-01 09:30:00'),
(13, '2016-08-01 00:00:00', '2016-08-01 11:00:00'),
(13, '2016-08-01 00:00:00', '2016-08-01 12:00:00'),
(13, '2016-08-01 00:00:00', '2016-08-01 15:00:00'),
(13, '2016-08-01 00:00:00', '2016-08-01 16:00:00'),
(13, '2016-08-02 00:00:00', '2016-08-02 09:30:00');
Query
;WITH cte
AS (SELECT *,
((Row_number()OVER(partition BY [adate] ORDER BY [time])-1)%2) + 1 AS seq_no,
((Row_number()OVER(partition BY [adate] ORDER BY [time])-1)/2) + 1 rang_no
FROM #Table1)
SELECT [card_no],
[adate],
time_in = Min(CASE WHEN seq_no = 1 THEN [time] END),
time_in = Min(CASE WHEN seq_no = 2 THEN [time] END)
FROM cte
GROUP BY [card_no],
[adate],
rang_no
Result:
card_no adate time_in time_in
------ ---------- ----------------------- -----------------------
13 2016-08-01 2016-08-01 09:30:00.000 2016-08-01 11:00:00.000
13 2016-08-01 2016-08-01 12:00:00.000 2016-08-01 15:00:00.000
13 2016-08-01 2016-08-01 16:00:00.000 NULL
13 2016-08-02 2016-08-02 09:30:00.000 NULL
Another way with OUTER APPLY (is used to get next row with time > than in current row) and ROW_NUMBER (with %2 to get only odd rows):
SELECT t.card_no,
t.adate,
t.[time],
t.time_in
FROM (
SELECT y.*,
p.[time] as time_in,
ROW_NUMBER() OVER (PARTITION BY y.card_no, y.adate ORDER BY y.[time])%2 as seq
FROM YourTable y
OUTER APPLY (
SELECT TOP 1 *
FROM YourTable
WHERE [time] > y.[time] and [adate] = y.adate
ORDER BY [time] ASC
) p
) as t
WHERE t.seq = 1
ORDER BY [time]
Output:
card_no adate time time_in
13 2016-08-01 2016-08-01 09:30:00 2016-08-01 11:00:00
13 2016-08-01 2016-08-01 12:00:00 2016-08-01 15:00:00
13 2016-08-01 2016-08-01 16:00:00 NULL
13 2016-08-02 2016-08-02 09:30:00 NULL
In order to get data for some reporting, I have to know how much lines have been inserted per hour in a table starting at a specific hour for a specific day. I already found a part of the solution in another question but I didn't manage to find a way to adapt it in my case. This is the code I've written so far:
SELECT DATEADD(HOUR, DATEDIFF(HOUR, 0, t.mydatetime), 0) AS HOUR_CONCERNED,
COUNT(*) AS NB_ROWS
FROM mytable t
WHERE CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, t.mydatetime))) = '2016-06-06'
GROUP BY DATEADD(HOUR, DATEDIFF(HOUR, 0, t.mydatetime), 0)
ORDER BY HOUR_CONCERNED;
It gives me the following results:
HOUR_CONCERNED NB_ROWS
------------------- --------
2016-06-06 10:00:00 2157
2016-06-06 11:00:00 60740
2016-06-06 12:00:00 66189
2016-06-06 13:00:00 77096
2016-06-06 14:00:00 90039
The problem is that I can't find a way to start my results at a specific time such as 9.30am and to get the number of rows per hour starting from this time. In other words, I'm looking for the number of rows between 9.30am and 10.30am, between 10.30am and 11.30am, etc. The results I'm looking for should look like this:
HOUR_CONCERNED NB_ROWS
------------------- --------
2016-06-06 09:30:00 3550
2016-06-06 10:30:00 33002
2016-06-06 11:30:00 42058
2016-06-06 12:30:00 55008
2016-06-06 13:30:00 72000
Is there an easy way to adapt my query and get those results ?
Given a specific starting time, you can get hour blocks by finding the number of minutes since your start time, and dividing by 60, then adding this number of hours back to the start time e.g.
DECLARE #StartTime DATETIME2(0) = '20160606 09:30';
WITH DummyData (mydatetime) AS
( SELECT TOP 200 DATEADD(MINUTE, ROW_NUMBER() OVER(ORDER BY [object_id]) - 1, #StartTime)
FROM sys.all_objects
)
SELECT HoursSinceStart = FLOOR(DATEDIFF(MINUTE, #StartTime, mydatetime) / 60.0),
Display = DATEADD(HOUR, FLOOR(DATEDIFF(MINUTE, #StartTime, mydatetime) / 60.0), #StartTime),
Records = COUNT(*)
FROM DummyData
WHERE myDateTime >= #StartTime
GROUP BY FLOOR(DATEDIFF(MINUTE, #StartTime, mydatetime) / 60.0)
ORDER BY Display;
Which gives:
HoursSinceStart Display Records
0 2016-06-06 09:30:00 60
1 2016-06-06 10:30:00 40
2 2016-06-06 11:30:00 60
3 2016-06-06 12:30:00 20
I have left the HoursSinceStart column in, to hopefully assist in deconstructing the logic contained in the Display column
The problem with this method is that it will only give you results for blocks that exist, if you also need those that don't you will need to generate all time blocks using a numbers table, then left join to your data:
You can quickly generate a series of numbers using this:
DECLARE #StartTime DATETIME2(0) = '20160606 09:30';
-- GENERATE 10 ROWS
WITH N1 AS (SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (N)),
-- CROSS JOIN THE 10 ROWS TO GET 100 ROWS
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
--CROSS JOIN THE 100 ROWS TO GET 10,000 ROWS
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
--APPLY ROW_NUMBER TO GET A SET OF NUMBERS FROM 0 - 99,999
Numbers (N) AS (SELECT ROW_NUMBER() OVER(ORDER BY N) - 1 FROM N3)
SELECT *,
TimeStart = DATEADD(HOUR, N, #StartTime),
TimeEnd = DATEADD(HOUR, N + 1, #StartTime)
FROM Numbers;
Which gives something like:
N TimeStart TimeEnd
--------------------------------------------------
0 2016-06-06 09:30:00 2016-06-06 10:30:00
1 2016-06-06 10:30:00 2016-06-06 11:30:00
2 2016-06-06 11:30:00 2016-06-06 12:30:00
3 2016-06-06 12:30:00 2016-06-06 13:30:00
4 2016-06-06 13:30:00 2016-06-06 14:30:00
5 2016-06-06 14:30:00 2016-06-06 15:30:00
6 2016-06-06 15:30:00 2016-06-06 16:30:00
7 2016-06-06 16:30:00 2016-06-06 17:30:00
Then you can left join your data to this (you will probably need an end time too);
DECLARE #StartTime DATETIME2(0) = '20160606 09:30',
#EndTime DATETIME2(0) = '20160606 15:30';
WITH DummyData (mydatetime) AS
( SELECT TOP 200 DATEADD(MINUTE, ROW_NUMBER() OVER(ORDER BY [object_id]) - 1, #StartTime)
FROM sys.all_objects
),
-- GENERATE NUMBERS
N1 AS (SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
Numbers (N) AS (SELECT ROW_NUMBER() OVER(ORDER BY N) - 1 FROM N3),
TimePeriods AS
( SELECT TimeStart = DATEADD(HOUR, N, #StartTime),
TimeEnd = DATEADD(HOUR, N + 1, #StartTime)
FROM Numbers
WHERE DATEADD(HOUR, N, #StartTime) < #EndTime
)
SELECT tp.TimeStart, tp.TimeEnd, Records = COUNT(dd.myDateTime)
FROM TimePeriods AS tp
LEFT JOIN DummyData AS dd
ON dd.mydatetime >= tp.TimeStart
AND dd.mydatetime < tp.TimeEnd
GROUP BY tp.TimeStart, tp.TimeEnd
ORDER BY tp.TimeStart;
Which will return 0 where there are no records:
TimeStart TimeEnd Records
---------------------------------------------------------
2016-06-06 09:30:00 2016-06-06 10:30:00 60
2016-06-06 10:30:00 2016-06-06 11:30:00 60
2016-06-06 11:30:00 2016-06-06 12:30:00 60
2016-06-06 12:30:00 2016-06-06 13:30:00 20
2016-06-06 13:30:00 2016-06-06 14:30:00 0
2016-06-06 14:30:00 2016-06-06 15:30:00 0
Try this:
SELECT DATEADD( MINUTE, 30, DATEADD(HOUR, DATEDIFF(HOUR, 0, DATEADD( MINUTE, -30, t.mydatetime)), 0)) AS HOUR_CONCERNED,
COUNT(*) AS NB_ROWS
FROM mytable t
WHERE CONVERT(DATETIME, FLOOR(CONVERT(FLOAT, t.mydatetime))) = '2016-06-06'
GROUP BY DATEADD(HOUR, DATEDIFF(HOUR, 0, DATEADD( MINUTE, -30, t.mydatetime)), 0)
ORDER BY HOUR_CONCERNED;
I added a 30 min offset into the GROUP BY function to treat 9:30 as 9:00, 10:30 as 10:00 and so on. In the select part I reverse this offset to give a proper interval.
The WHERE condition in your query needs to change though for performance reasons. Instead of truncating timestamps to a nearest day, you should filter by a range:
WHERE t.mydatetime >= CONVERT( DATETIME, '2016-06-06' ) AND t.mydatetime < CONVERT( DATETIME, '2016-06-07' )
You need to have the time in the where clause, and set a greater than against the time you want to measure from? Also, you can use DATEPART to get the hours.
SELECT NB_ROWS = COUNT(*)
,HOUR_CONCERNED = DATEPART(HOUR, InsertedDate)
FROM table
WHERE InsertedDate = '20160531'
AND InsertedDate> time
GROUP BY DATEPART(HOUR, InsertedDate)
I have a data set, which looks like this:
ResourceID RequirementId ProjectID Startdate EndDate BillingPercentage
-------------------- -------------------- -------------------- ----------------------- ----------------------- ---------------------------------------
1 5066 7505 2015-09-15 00:00:00.000 2015-09-30 00:00:00.000 50
2 4748 7499 2015-09-10 00:00:00.000 2015-09-20 00:00:00.000 50
I want to calculate range and corresponding billing % for that particular month my query is:
INSERT INTO #DateTimeline
SELECT #MonthStartDate AS OSTARTDATE,#MonthEndDate AS OENDDATE,0
INSERT INTO #DateTimeline
SELECT Startdate AS OSTARTDATE,EndDate AS OENDDATE,BillingPercentage From #RESOURCE_UNBILLED Order by Startdate
INSERT INTO #DateTimeline
SELECT EndDate AS OSTARTDATE,EndDate AS OENDDATE,BillingPercentage From #RESOURCE_UNBILLED Order by Startdate
And data looks like following:
SerialNo OSTARTDATE OENDDATE BillingPercentage
----------- ----------------------- ----------------------- ---------------------------------------
1 2015-09-01 00:00:00.000 2015-09-30 00:00:00.000 0
2 2015-09-10 00:00:00.000 2015-09-20 00:00:00.000 50
3 2015-09-15 00:00:00.000 2015-09-30 00:00:00.000 50
4 2015-09-20 00:00:00.000 2015-09-20 00:00:00.000 50
5 2015-09-30 00:00:00.000 2015-09-30 00:00:00.000 50
I want to retrive data like following
OSTARTDATE OENDDATE BillingPercentage
----------- ----------------------- ----------------------- ---------------------------------------
2015-09-01 00:00:00.000 2015-09-10 00:00:00.000 0
2015-09-10 00:00:00.000 2015-09-15 00:00:00.000 50
2015-09-15 00:00:00.000 2015-09-20 00:00:00.000 100
2015-09-20 00:00:00.000 2015-09-30 00:00:00.000 50
Please suggest how can I get this also can I use pivot here?
Use a table variable to store your #dateStamps with columns: SerialNo, OSTARTDATE and OENDDATE.
Try this query:
SELECT d.SerialNo, d.OSTARTDATE, d.OENDDATE
, ( SELECT SUM(t.BillingPercentage)
FROM yourTable t
WHERE d.OENDDATE BETWEEN t.Startdate AND t.EndDate
OR d.OSTARTDATE BETWEEN t.Startdate AND t.EndDate
OR (d.OSTARTDATE > t.Startdate AND d.OENDDATE < t.EndDate)
) AS BillingPercentage
FROM
#dateStamps d
My complete code is:
DECLARE #DatePart as int = 5
;WITH dateStamps AS (
SELECT 1 As SerialNo, CAST('2015-' + CONVERT(varchar, MONTH(MIN(t.Startdate))) + '-01 00:00:00.000' As datetime) AS OSTARTDATE
, CAST('2015-' + CONVERT(varchar, MONTH(MIN(t.Startdate))) + '-01 00:00:00.000' As datetime) + (#DatePart - 1) AS OENDDATE
FROM yourTable t
UNION ALL
SELECT ds.SerialNo + 1, ds.OSTARTDATE + #DatePart, ds.OSTARTDATE + (#DatePart * 2 - 1)
FROM dateStamps ds
WHERE MONTH(OSTARTDATE + #DatePart) <= MONTH(ds.OSTARTDATE)
)
SELECT d.SerialNo, d.OSTARTDATE, d.OENDDATE
, ( SELECT SUM(t.BillingPercentage)
FROM t
WHERE d.OENDDATE BETWEEN t.Startdate AND t.EndDate
OR d.OSTARTDATE BETWEEN t.Startdate AND t.EndDate
OR (d.OSTARTDATE > t.Startdate AND d.OENDDATE < t.EndDate)
) AS BillingPercentage
FROM
dateStamps d
I have two working shifts: 8:00:00 to 16:30:00 and 20:00:00 to 06:00:00. I want to create a stored procedure that will retrieve data from an SQL table when I pass the date
This is my tables Table1
ID DateTime EmpID
-------------------------------------
47 2014-12-07 08:00:00 1111
47 2014-12-07 15:25:00 1235
47 2014-12-07 23:55:00 4569
47 2014-12-08 00:00:00 4563
47 2014-12-08 02:00:00 7412
59 2014-12-08 04:00:00 8523
59 2014-12-05 10:30:00 5632
Table Product
ID DateTime ProductMade
47 2014-12-07 11:00:00 Milk
47 2014-12-07 08:00:00 Juice
47 2014-12-08 00:00:00 Bread
47 2014-12-08 04:00:00 Cakes
47 2014-12-07 21:00:00 Juice
89 2014-12-01 04:00:00 bread
query for shift 2 18:00 to 06:00
select Count(EmpID) as ID,Count (ProductMade) ProductsTotal, Count(EmpID) * Count (ProductMade) as Total
from Table 1 as T1
inner join Table_Product as Prod on t1.ID = Prod.ID
where T1.DateTime BETWEEN DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()-2), 0) + '18:00' and DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()-1), 0) + '06:00' and DepartmentID=47
So this will get all the records that has the same ID matching
Then I have to do another query for the first shift.
between 08:00 to 16:30
select Count(EmpID) as ID,Count (ProductMade) ProductsTotal, Count(EmpID) * Count (ProductMade) as Total
from Table 1 as T1
inner join Table_Product as Prod on t1.ID = Prod.ID
where DATEDIFF(day, CONVERT(VARCHAR(10), GETDATE(),110), CONVERT(VARCHAR(10), T1.DateTime,110))=-2 and DATEPART(HOUR,T1.DateTime) BETWEEN '07' AND '16' and DepartmentID=47
OutPUT FirstShift 08 :00 to 16:30
ID ProductMade Total
2 2 4
OutPut Second Shift 20:00 to 06:00
ID ProductMade Total
3 3 9
so the second shift request a the startdate of -2 and the end date of -1 this is the part thats different from the day shift. cause i will pass the number of days previous i want to go backwards from a select box
This will product something in 1 go. I'm still not sure what output you are looking for. What does the DateTime in the Table_Product represent?
DECLARE #days int
SET #days = 4;
WITH Tab as (
Select case when DATEPART(hour, t.DateTime) between 8 and 16 then 'A' else 'B' end AS Shift, *
from Table1 t
where t.DateTime between DateAdd(hour, 8, Convert(datetime, Floor(Convert(float, Convert(datetime, GetDate())) - #days)))
and DateAdd(hour, 30, Convert(datetime, Floor(Convert(float, Convert(datetime, GetDate())) - #days)))
),
Prod as (
Select case when DATEPART(hour, t.DateTime) between 8 and 16 then 'A' else 'B' end AS Shift, *
from Table_Product t
where t.DateTime between DateAdd(hour, 8, Convert(datetime, Floor(Convert(float, Convert(datetime, GetDate())) - #days)))
and DateAdd(hour, 30, Convert(datetime, Floor(Convert(float, Convert(datetime, GetDate())) - #days))))
Select ID, ProductMake, Shift, Count(*), (Select Count(*) from Tab where ID = t1.ID and Shift = t1.Shift) Total from Prod t1
GROUP BY ID, Shift, ProductMake
Something like this?
where ((#shift = 1 and t1.datetime between ... ) or (#shift = 2 and datediff ... ))