Split DATEDIFF into separate months - sql

I currently have an issue whereby I am doing DATEDIFF in minutes between a start date and end date, however I when this date goes over into a new month I need the figures to be separate for each month.
Please see example data (both Text and Image view);
SELECT [BookingNum]
,[StartDate]
,[EndDate]
,[Location]
,DATEPART(m,startdate) AS [Month]
,DATEDIFF(MINUTE,StartDate,EndDate) AS [Minutes]
FROM [Test].[dbo].[Booking]
BookingNum StartDate EndDate Location Month Minutes
1 2019-02-05 12:54:00.000 2019-02-08 15:00:00.000 Area 1 2 4446
2 2019-05-02 10:41:00.000 2019-05-10 12:39:00.000 Area 2 5 11638
3 2019-06-01 10:30:00.000 2019-06-04 09:25:00.000 Area 3 6 4255
4 2019-02-02 09:41:00.000 2019-04-20 11:54:00.000 Area 1 2 111013
5 2019-03-29 19:09:00.000 2019-04-02 10:41:00.000 Area 3 3 5252
For rows 4 & 5 there would need to be additional rows as they go across multiple months.
Example for the data in row 4, I would want to see;
StartDate EndDate Location Month Minutes
2019-02-02 09:41:00.000 2019-02-28 23:59:00.000 Area 1 2 38298
2019-03-01 00:00:00.000 2019-03-31 23:59:00.000 Area 1 3 44639
2019-04-01 00:00:00.000 2019-04-20 23:59:00.000 Area 1 4 28074
This would then give me the total minutes for that month only between the start and end date.
Any help much appreciated.

Edit: Recursive CTE should do the trick! Basically, use recursion to keep getting the start date through the lesser of the EOM and the end date, until ultimately you reach the end date.
Fiddle
DECLARE #tbl TABLE (bookingnum INT, sd DATETIME, ed DATETIME)
INSERT INTO #tbl VALUES
(1, '2/5/2019 12:54 PM', '2/8/2019 3:00 PM'),
(2, '5/2/2019 10:41 AM', '5/10/2019 12:39 PM'),
(3, '6/1/2019 10:30 AM', '6/4/2019 9:25 AM'),
(4, '2/2/2019 9:41 AM', '5/20/2019 11:54 AM'),
(5, '3/29/2019 7:09 PM', '4/2/2019 10:41 AM')
;WITH cte AS (
SELECT bookingnum, sd, DATEADD(DAY, 1, EOMONTH(sd)) eom, ed,
CASE WHEN DATEADD(DAY, 1, EOMONTH(sd)) < ed THEN DATEADD(DAY, 1, EOMONTH(sd)) else ed END AS applied_ed
FROM #tbl
UNION ALL
SELECT bookingnum, applied_ed, DATEADD(DAY, 1, EOMONTH(applied_ed)) eom, ed,
CASE WHEN DATEADD(DAY, 1, EOMONTH(applied_ed)) < ed THEN DATEADD(DAY, 1, EOMONTH(applied_ed)) else ed END AS applied_ed
FROM cte
WHERE applied_ed < ed
)
SELECT bookingnum, sd, applied_ed AS ed, DATEDIFF(MINUTE, sd, applied_ed) minutes
FROM cte
ORDER BY bookingnum, sd
Returns:
bookingnum sd ed minutes
1 2019-02-05 12:54:00.000 2019-02-08 15:00:00.000 4446
2 2019-05-02 10:41:00.000 2019-05-10 12:39:00.000 11638
3 2019-06-01 10:30:00.000 2019-06-04 09:25:00.000 4255
4 2019-02-02 09:41:00.000 2019-03-01 00:00:00.000 38299
4 2019-03-01 00:00:00.000 2019-04-01 00:00:00.000 44640
4 2019-04-01 00:00:00.000 2019-05-01 00:00:00.000 43200
4 2019-05-01 00:00:00.000 2019-05-20 11:54:00.000 28074
5 2019-03-29 19:09:00.000 2019-04-01 00:00:00.000 3171
5 2019-04-01 00:00:00.000 2019-04-02 10:41:00.000 2081

This can be achieved using recursive CTE as follows. This calculates multiple months between startdate and enddate.
Fiddle: http://sqlfiddle.com/#!18/26568/4
create table #temp(
BookingNum int,
StartDate datetime,
EndDate datetime,
Location varchar(25),
)
insert into #temp
values(1,'2019-02-05 12:54:00','2019-02-08 15:00:00','Area 1'),
(2,'2019-05-02 10:41:00','2019-05-10 12:39:00','Area 2'),
(3,'2019-06-01 10:30:00','2019-06-04 09:25:00','Area 3'),
(4,'2019-02-02 09:41:00','2019-05-20 11:54:00','Area 1'),
(5,'2019-03-29 19:09:00','2019-04-02 10:41:00','Area 3')
;WITH cte AS
(
SELECT BookingNum,
StartDate,
CASE
WHEN DATEPART(m, EndDate) > DATEPART(m, startdate)
THEN DATEADD(s, -1, DATEADD(mm, DATEDIFF(m, 0, startdate) + 1, 0))
ELSE EndDate
END AS EndDate,
Location,
DATEPART(m, EndDate) - DATEPART(m, startdate) AS MonthDiff
FROM #temp
UNION ALL
SELECT cte.BookingNum,
CASE
WHEN cte.MonthDiff > 0
THEN DATEADD(month, DATEDIFF(month, 0, DATEADD(month, 1, cte.StartDate)), 0)
ELSE cte.StartDate
END AS startDate,
CASE
WHEN cte.MonthDiff > 0 AND DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, DATEADD(month, 1, cte.StartDate)) + 1, 0)) < t.EndDate
THEN DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, DATEADD(month, 1, cte.StartDate)) + 1, 0))
ELSE t.EndDate
END AS EndDate,
cte.Location,
(cte.MonthDiff - 1) MonthDiff
FROM cte
INNER JOIN #temp t ON cte.BookingNum = t.BookingNum
WHERE cte.MonthDiff > 0
)
SELECT BookingNum,
StartDate,
EndDate,
Location,
DATEPART(m, startdate) AS month,
DATEDIFF(minute, startdate, enddate) AS minutes
FROM cte
ORDER BY 1;
drop table #temp
Result:
BookingNum StartDate EndDate Location month minutes
----------- ----------------------- ----------------------- ------------------------- ----------- -----------
1 2019-02-05 12:54:00.000 2019-02-08 15:00:00.000 Area 1 2 4446
2 2019-05-02 10:41:00.000 2019-05-10 12:39:00.000 Area 2 5 11638
3 2019-06-01 10:30:00.000 2019-06-04 09:25:00.000 Area 3 6 4255
4 2019-02-02 09:41:00.000 2019-02-28 23:59:59.000 Area 1 2 38298
4 2019-03-01 00:00:00.000 2019-03-31 00:00:00.000 Area 1 3 43200
4 2019-04-01 00:00:00.000 2019-04-30 00:00:00.000 Area 1 4 41760
4 2019-05-01 00:00:00.000 2019-05-20 11:54:00.000 Area 1 5 28074
5 2019-03-29 19:09:00.000 2019-03-31 23:59:59.000 Area 3 3 3170
5 2019-04-01 00:00:00.000 2019-04-02 10:41:00.000 Area 3 4 2081

To achieve this you will need to create an additional table to join to that contains the months. You would then join to that table where the month of the date is between the dates in the calendar table, to do this you need to use a dateadd/datediff function to round your date to the first of the month e.g.: DATEADD(month, DATEDIFF(month, 0, StartDate),0). This works by calculating the difference in months between some random start date (in this case 0, I.e. 1/1/1900) and then adding those months back on to the start date.
Then you will need to round your start or end date up or down to the end of the month if they are not in the same month as the calendar table record, which will allow you to do a new calculation for the time.
The whole code would look something like this:
CREATE TABLE #MonthDate
(MonthDate date PRIMARY KEY);
INSERT INTO #MonthDate (MonthDate)
VALUES ('20190101'),('20190201'),('20190301'),('20190401'),('20190501'),('20190601');
WITH RoundedDates As
(SELECT b.StartDate,
B.EndDate,
DATEADD(month, DATEDIFF(month, 0, b.StartDate),0) AS RoundedStartDate,
DATEADD(month, DATEDIFF(month, 0, b.EndDate),0) AS RoundedEndDate
FROM Test.dbo.Booking AS b)
SELECT rd.StartDate
, rd.EndDate
, DATEDIFF(minute, CASE WHEN rd.RoundedStartDate = md.MonthDate THEN rd.StartDate ELSE md.MonthDate END, CASE WHEN rd.RoundedEndDate = md.MonthDate THEN rd.EndDate ELSE DATEADD(month,1,md.MonthDate) END) AS Minutes
FROM RoundedDates AS rd
INNER JOIN #MonthDate as md
ON md.MonthDate BETWEEN rd.RoundedStartDate AND rd.RoundedEndDate
http://sqlfiddle.com/#!18/70730/2

Related

SQL expand datefrom and dateto span of multiple years to multiple rows

I have the following input table with an id and start and enddate. I want to expand this to multiple rows when start and enddate span over multiple years, capping on the end of the year.
drop table if exists #policies;
create table #policies (
id int,
[start_date] datetime,
end_date datetime
);
insert into #policies (id, [start_date], end_date)
values
(1, '2019-01-01', '2021-12-31'),
(2, '2018-01-01', '2020-12-31'),
(3, '2011-01-01', '2013-12-31');
select * from #policies order by [id];
id start_date end_date
1 2019-01-01 00:00:00.000 2021-12-31 00:00:00.000
2 2018-01-01 00:00:00.000 2020-12-31 00:00:00.000
3 2011-01-01 00:00:00.000 2013-12-31 00:00:00.000
Expexted result:
drop table if exists #policies_expected;
create table #policies_expected (
id int,
[start_date] datetime,
end_date datetime
);
insert into #policies_expected (id, [start_date], end_date)
values
(1, '2019-01-01', '2019-12-31'),
(1, '2020-01-01', '2020-12-31'),
(1, '2021-01-01', '2021-12-31'),
(2, '2018-01-01', '2018-12-31'),
(2, '2019-01-01', '2019-12-31'),
(2, '2020-01-01', '2020-12-31'),
(3, '2011-01-01', '2011-12-31'),
(3, '2012-01-01', '2012-12-31'),
(3, '2013-01-01', '2013-12-31');
select * from #policies_expected order by [id], start_date
id start_date end_date
1 2019-01-01 00:00:00.000 2019-12-31 00:00:00.000
1 2020-01-01 00:00:00.000 2020-12-31 00:00:00.000
1 2021-01-01 00:00:00.000 2021-12-31 00:00:00.000
2 2018-01-01 00:00:00.000 2018-12-31 00:00:00.000
2 2019-01-01 00:00:00.000 2019-12-31 00:00:00.000
2 2020-01-01 00:00:00.000 2020-12-31 00:00:00.000
3 2011-01-01 00:00:00.000 2011-12-31 00:00:00.000
3 2012-01-01 00:00:00.000 2012-12-31 00:00:00.000
3 2013-01-01 00:00:00.000 2013-12-31 00:00:00.000
I tried to solve this with a recursive cte, which worked for one row:
with recursive cte(id, start_date, end_date) as (
select
id,
start_date,
dateadd(day, -1, dateadd(year, 1, start_date)) as end_date
from
#policies
where
id = 1 -- this filter is needed to make it work for one id
union all
select
id,
dateadd(year, 1, start_date) as start_date,
dateadd(day, -1, dateadd(year, 2, start_date)) as end_date
from
cte
where
start_date < dateadd(year, -1, (select max(end_date) from #policies where id=1))
)
select * from cte;
id start_date end_date
1 2019-01-01 00:00:00.000 2019-12-31 00:00:00.000
1 2020-01-01 00:00:00.000 2020-12-31 00:00:00.000
1 2021-01-01 00:00:00.000 2021-12-31 00:00:00.000
The problem here is
select max(end_date) from #policies where id=1
I am not sure how to do this per id, if I would remove the where clause in my solution, it would take the max enddate for the whole table. This needs to happen per id.
How can I solve this, I am open for other solutions as well.

Time until midnight between two date and time columns

I need help with my query to calculate the time until midnight between two date and time columns
break down by day
This is the main table:
ID
Start_Time
End_time
DateDiff
32221
01-01-2022 13:10:00
01-03-2022 13:10:00
2880
My query:
SELECT
start_time.ID,
start_time.Date_Time AS Start_time,
end_time.Date_Time AS End_time,
DATEDIFF(minute, start_time.Date_Time, end_time.Date_Time) AS DateDiff
FROM
Main
what I need is similar to this:
ID
Date_start
End_time
DateDiff
32221
01-01-2022 13:10:00
01-01-2022 23:59:59
654
32221
01-02-2022 00:00:00
01-02-2022 23:59:59
1440
32221
01-03-2022 00:00:00
01-03-2022 13:10:00
781
how i can do that?
You can loop through the times, always adding the time untill midnight, untill your 'start_time + 1 day' is bigger than your end_time.
The below code can be run directly in SQL (mind the date notation, my SQL is in united states notation, so if yours is in Europe this will give you back results for 3 months instead of 3 days);
DECLARE #start_time datetime2 = '01/01/2022 13:00:00';
DECLARE #end_time datetime2 = '03/01/2022 14:00:00';
DECLARE #daily_end_time datetime2=NULL;
DECLARE #Table Table (start_time datetime2, end_time datetime2, diff nvarchar(8));
DECLARE #diff_minutes_start int = DATEDIFF(MINUTE,#start_time,DateDiff(day,0,dateadd(day,1,#start_time)));
DECLARE #diff_minutes_end int = DATEDIFF(minute,#end_time,DateDiff(day,0,dateadd(day,1,#end_time)))
SET #daily_end_time = DATEADD(mi,#diff_minutes_start,#start_time)
WHILE #daily_end_time < #end_time
BEGIN
INSERT INTO #Table (start_time,end_time,diff)
VALUES (
#start_time,
CASE WHEN DATEADD(day,1,#daily_end_time) > #end_time THEN #end_time ELSE
#daily_end_time END,
CASE WHEN DATEADD(day,1,#daily_end_time) > #end_time THEN #diff_minutes_end ELSE
#diff_minutes_start END )
SET #daily_end_time = DATEADD(mi,#diff_minutes_start,#start_time)
SET #start_time = DATEADD(mi,1,#daily_end_time);
select #diff_minutes_start =
DATEDIFF(MINUTE,#start_time,DateDiff(day,0,dateadd(day,1,#start_time)));
select #diff_minutes_end = DATEDIFF(minute,#end_time,DateDiff(day,0,dateadd(day,1,#end_time)))
END
SELECT * FROM #Table
And the results:
You may use a recursive CTE as the following:
With CTE As
(
Select ID, Start_Time, End_time, DATEADD(Second, -1, DATEADD(Day, DATEDIFF(Day,0, Start_Time), 1)) et
From main
Union All
Select C.ID, DATEADD(Second, 1, C.et), C.End_time, DATEADD(Day, 1, C.et)
From CTE C Join main T
On C.ID = T.ID
Where DATEADD(Second, 1, C.et) <= C.End_time
)
Select ID, Start_Time,
Case When End_Time <= et Then End_Time Else et End As End_Time,
DATEDIFF(Minute, Start_Time, DATEADD(Second, 1, Case When End_Time <= et Then End_Time Else et End)) As [DateDiff]
From CTE
Order By ID, Start_Time
See a demo with extended data sample from db<>fiddle.
You can also solve this with a tally table, using the expanded (to show different cases) sample data
ID
StartTime
EndTime
32221
2022-01-01 13:10:00
2022-01-03 13:10:00
32222
2022-02-02 10:10:00
2022-02-02 17:10:00
32223
2022-03-03 19:10:00
2022-03-04 08:10:00
32224
2022-04-04 19:10:00
2022-04-08 08:10:00
and the code
with cteSampleData as ( --Enter some sample data, include spans of 0, 1, and >1 days
SELECT * --Note that we need CONVERT to make sure the dates are treated as datetime not string!
FROM (VALUES(32221, CONVERT(datetime2(0), '01-01-2022 13:10:00'), CONVERT(datetime2(0), '01-03-2022 13:10:00') )
, (32222, '02-02-2022 10:10:00', '02-02-2022 17:10:00')
, (32223, '03-03-2022 19:10:00', '03-04-2022 08:10:00')
, (32224, '04-04-2022 19:10:00', '04-08-2022 08:10:00')
) as Samp(ID, StartTime, EndTime)
), cteWithControl as ( --Add some fields to make testing cledarer - you could do this as part of a subsequent step instead
SELECT *
, CONVERT(date, StartTime) as StartDate , CONVERT(date, EndTime) as EndDate
, DATEDIFF(day, StartTime , EndTime) as DiffDays
--, DATEDIFF(day, CONVERT(date, StartTime) , CONVERT(date, EndTime)) as DiffDays
FROM cteSampleData
), cteTally as ( --Get a list of integers to represent days, assume nothing lasts longer than a year
SELECT top 365 ROW_NUMBER() over (ORDER BY name) as Tally
FROM sys.objects --just a table we know has over 300 rows, look up tally tables for other generation methods
)--The real work begins below, partition the data into "same day" and "multi-day" spans
, cteSet as (
SELECT ID, StartTime, EndTime, DiffDays, 1 as DayNumber
FROM cteWithControl WHERE DiffDays = 0
UNION ALL
SELECT ID --For multi-day, cross with the tally table and treat first and last days special
, CASE WHEN T.Tally = 1 THEN StartTime --For the first day the start time is the real time
ELSE DATEADD (day, T.Tally - 1, startdate) END as StartTime --Otherwise it's the start of the day
, CASE WHEN T.Tally = DiffDays + 1 THEN EndTime --For the last day the end is the real end
ELSE DATEADD (second, -1, CONVERT(DATETIME2(0), DATEADD (day, T.Tally, startdate)))
END as EndTime --otherwise 1 second less than the next day
, DiffDays, Tally as DayNumber
FROM cteWithControl as D CROSS JOIN cteTally as T
WHERE DiffDays > 0 AND T.Tally <= D.DiffDays + 1
)--Now we display the results and calculate the length (in minutes) of each span
SELECT *
, DATEDIFF(MINUTE, StartTime, EndTime) as DateDiff
FROM cteSet
ORDER BY ID, DayNumber
we get the output
ID
StartTime
EndTime
DiffDays
DayNumber
DateDiff
32221
2022-01-01 13:10:00
2022-01-01 23:59:59
2
1
649
32221
2022-01-02 00:00:00
2022-01-02 23:59:59
2
2
1439
32221
2022-01-03 00:00:00
2022-01-03 13:10:00
2
3
790
32222
2022-02-02 10:10:00
2022-02-02 17:10:00
0
1
420
32223
2022-03-03 19:10:00
2022-03-03 23:59:59
1
1
289
32223
2022-03-04 00:00:00
2022-03-04 08:10:00
1
2
490
32224
2022-04-04 19:10:00
2022-04-04 23:59:59
4
1
289
32224
2022-04-05 00:00:00
2022-04-05 23:59:59
4
2
1439
32224
2022-04-06 00:00:00
2022-04-06 23:59:59
4
3
1439
32224
2022-04-07 00:00:00
2022-04-07 23:59:59
4
4
1439
32224
2022-04-08 00:00:00
2022-04-08 08:10:00
4
5
490

How to create date(day, week, month) range table

I have a question about a datetime table in SQL Server.
This is my code. I can make daily
SELECT DAYDATE AS BASE_DT
FROM(
SELECT CONVERT(CHAR(10), DATEADD(D, NUMBER, '2019-01-01'), 120) AS DAYDATE
FROM MASTER..SPT_VALUES WITH(NOLOCK)
WHERE TYPE = 'P'
AND NUMBER <= DATEDIFF(D, '2019-01-01', getdate())
) DATE_TABLE
I can make daily column but I don't know how to add week, month column
Like this.
Please, check this issue. Thank you.
You can use the following query:
SET DATEFIRST 1; -- Set first day of week to Monday
SELECT
DAYDATE AS BASE_DT
-- last day (always a Sunday) of the current week
, CONVERT(DATE, DATEADD(D, 7 - DATEPART(WEEKDAY, DAYDATE), DAYDATE)) AS WEEK_DT
-- last day of the current month
, CONVERT(DATE, DATEADD(month, ((YEAR(DAYDATE) - 1900) * 12)
+ MONTH(DAYDATE), -1)) AS MONTH_DT
FROM (
SELECT CONVERT(DATE, DATEADD(D, NUMBER, '2019-01-01')) AS DAYDATE
FROM MASTER..SPT_VALUES WITH(NOLOCK)
WHERE TYPE = 'P'
AND NUMBER <= DATEDIFF(D, '2019-01-01', getdate())
) DATE_TABLE
Output:
BASE_DT WEEK_DT MONTH_DT
----------------------------------
2019-01-01 2019-01-06 2019-01-31
2019-01-02 2019-01-06 2019-01-31
2019-01-03 2019-01-06 2019-01-31
2019-01-04 2019-01-06 2019-01-31
...
2019-02-01 2019-02-03 2019-02-28
2019-02-02 2019-02-03 2019-02-28
2019-02-03 2019-02-03 2019-02-28
...
2021-01-09 2021-01-10 2021-01-31
2021-01-10 2021-01-10 2021-01-31
2021-01-11 2021-01-17 2021-01-31
Use DATEADD and DATEPART, like this:
with d as
(
SELECT CONVERT(CHAR(10), DATEADD(D, NUMBER, '2019-01-01'), 120) AS DAYDATE
FROM MASTER..SPT_VALUES
WHERE TYPE = 'P'
AND NUMBER <= DATEDIFF(D, '2019-01-01', getdate())
)
SELECT DAYDATE AS BASE_DT,
dateadd(day,1-datepart(weekday, daydate),daydate) WEEK_DT,
dateadd(day,1-datepart(day, daydate),daydate) MONTH_DT
FROM d

single query to retrieve data in sql for different shift patterns

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 ... ))

Dense_rank and sum

I have this common table expression
WITH total_hour
AS (
SELECT
employee_id,
SUM(ROUND(CAST(DATEDIFF(MINUTE, start_time, finish_time) AS NUMERIC(18, 0)) / 60, 2)) AS total_h
FROM Timesheet t
WHERE t.employee_id = #employee_id
AND DENSE_RANK() OVER (
ORDER BY DATEDIFF(DAY, '20130925', date_worked) / 7 DESC ) = #rank
GROUP BY t.personnel_id
)
This is the sample data:
ID employee_id worked_date start_time finish_time
1 1 2013-09-25 09:00:00 17:30:00
2 1 2013-09-26 07:00:00 17:00:00
8 1 2013-10-01 09:00:00 17:00:00
9 1 2013-10-04 09:00:00 17:00:00
12 1 2013-10-07 09:00:00 17:00:00
13 1 2013-10-30 09:00:00 17:00:00
14 1 2013-10-28 09:00:00 17:00:00
15 1 2013-11-01 09:00:00 17:00:00
Supposed Wednesday is the first day of the week and my based date is 2013-09-25. I want to get the total number of hours worked from 09-25 to 10-01 when #rank is 1 and total hour from 10-02 to 10-08 when #rank=2 and so on.
Thanks
To get the number of hours worked for an employee within a particular week, just use a suitable WHERE criteria. No need to use DENSE_RANK or similar windowed functions for this.
Assuming you have a #Week parameter, that contains an integer (0 for current week, 1 for last week, 2 for week before that, etc.):
SELECT
employee_id
SUM(ROUND(CAST(DATEDIFF(MINUTE, start_time, finish_time) AS NUMERIC(18, 0)) / 60, 2)) AS total_h
FROM
Timesheet t
WHERE
t.employee_id = #employee_id AND
date_worked BETWEEN DATEADD(ww, DATEDIFF(ww,0,GETDATE()) - #Week, 0)
AND DATEADD(ww, DATEDIFF(ww,0,GETDATE()) - #Week, 0) + 7
Here, I've used the current date (GETDATE()) as the base date, but you could just replace it with 20130925, if that's what you need.