Total Minutes by Hour - sql-server

I have two fields in a data table - "startTime" and "endTime." These two fields represent a duration of time the user spent on a particular task. These are varchar fields. So, let's say we have a startTime of "21:05:00" and an endTime of "22:09:00." I need the code to sum the total number of minutes spent in hour 21, and the 22 hundred hour separately (i.e. 9 minutes). So, not just a simple minute difference, but a breakdown by hour.
What might be the best way to do that?
Thus far, I have created a table that will return all possible hours in a 24-hour period. Here's a sample:
Hour startTime endTime
0 2015-01-01 00:00:00.000 2015-01-01 01:00:00.000
1 2015-01-01 01:00:00.000 2015-01-01 02:00:00.000
2 2015-01-01 02:00:00.000 2015-01-01 03:00:00.000
And I have converted the startTime field from varchar to dateteime and called it sessionHour:
Convert(datetime, startTime) As sessionHour
Additionally, I was able to get the hour of the startTime by doing:
DateAdd(Minute, 60 * (DateDiff(Minute, 0, startTime) / 60), 0) As hourOf
Beyond that, I am lost as to how to parse out the minutes per hour.

You are very close. You just need to combine the numbers table with the data. I'll use CROSS APPLY for it. Here is SQLFiddle with the final solution.
Sample data
DECLARE #Durations TABLE (ID int IDENTITY(1,1), StartTime datetime, EndTime datetime);
INSERT INTO #Durations VALUES
('2015-01-01 21:05:00', '2015-01-01 22:09:00'),
('2015-01-01 01:05:00', '2015-01-01 01:20:00'),
('2015-01-01 11:05:00', '2015-01-01 13:09:00'),
('2015-01-01 15:05:00', '2015-01-01 17:50:00'),
('2015-01-01 16:30:00', '2015-01-01 17:20:00');
I'll use datetime type from the beginning, since you've converted your varchar values to proper datetime.
I'll use a table of numbers. It should have as many rows as the longest duration in hours in your data. It could be more than 24. In general, it is useful to have such table in a database for other reports.
DECLARE #Numbers TABLE (Number int);
INSERT INTO #Numbers VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
-- Number of rows in this table should be more than the longest duration in hours
I'll need some reference point in time for removing minute part of the datetime. It could be any date-time as long as it doesn't have minutes and seconds.
DECLARE #VarStart datetime;
SET #VarStart = '2000-01-01';
Main step - Expand the data
SELECT *
FROM
#Durations AS D
CROSS APPLY
(
SELECT N.Number
FROM #Numbers AS N
WHERE N.Number <= DATEDIFF(hour, StartTime, EndTime)
) AS CA_Number
ORDER BY ID;
ID StartTime EndTime Number
1 2015-01-01 21:05:00 2015-01-01 22:09:00 0
1 2015-01-01 21:05:00 2015-01-01 22:09:00 1
2 2015-01-01 01:05:00 2015-01-01 01:20:00 0
3 2015-01-01 11:05:00 2015-01-01 13:09:00 0
3 2015-01-01 11:05:00 2015-01-01 13:09:00 1
3 2015-01-01 11:05:00 2015-01-01 13:09:00 2
4 2015-01-01 15:05:00 2015-01-01 17:50:00 0
4 2015-01-01 15:05:00 2015-01-01 17:50:00 1
4 2015-01-01 15:05:00 2015-01-01 17:50:00 2
5 2015-01-01 16:30:00 2015-01-01 17:20:00 0
5 2015-01-01 16:30:00 2015-01-01 17:20:00 1
You can see that we created several rows for each original row depending on the duration of the original row. The rest is simple arithmetic.
Minutes per hour
SELECT *
,DATEDIFF(minute, MaxStart, MinEnd) AS MinutesPerHour
FROM
#Durations AS D
CROSS APPLY
(
SELECT N.Number
FROM #Numbers AS N
WHERE N.Number <= DATEDIFF(hour, StartTime, EndTime)
) AS CA_Number
CROSS APPLY
(
SELECT
DATEADD(hour, CA_Number.Number, StartTime) AS HourStart
,DATEADD(hour, CA_Number.Number+1, StartTime) AS HourEnd
) AS CA_HourEnd
CROSS APPLY
(
-- Truncate to 1 hour.
SELECT
DATEADD(hour, DATEDIFF(hour, #VarStart, HourStart), #VarStart) AS HourStartFinal
,DATEADD(hour, DATEDIFF(hour, #VarStart, HourEnd), #VarStart) AS HourEndFinal
) AS CA_HourEndFinal
-- Intersect intervals [StartTime, EndTime] with [HourStartFinal, HourEndFinal]
CROSS APPLY
(
SELECT
CASE WHEN StartTime > HourStartFinal THEN StartTime ELSE HourStartFinal END AS MaxStart
,CASE WHEN EndTime < HourEndFinal THEN EndTime ELSE HourEndFinal END AS MinEnd
) AS CA_Intersect
ORDER BY ID;
In CA_HourEnd and CA_HourEndFinal I calculate the hour boundaries using the Number. Then intersect two intervals and calculate the number of minutes for each intersection. This is the result set:
ID StartTime EndTime Number HourStart HourEnd HourStartFinal HourEndFinal MaxStart MinEnd MinutesPerHour
1 2015-01-01 21:05:00 2015-01-01 22:09:00 0 2015-01-01 21:05:00 2015-01-01 22:05:00 2015-01-01 21:00:00 2015-01-01 22:00:00 2015-01-01 21:05:00 2015-01-01 22:00:00 55
1 2015-01-01 21:05:00 2015-01-01 22:09:00 1 2015-01-01 22:05:00 2015-01-01 23:05:00 2015-01-01 22:00:00 2015-01-01 23:00:00 2015-01-01 22:00:00 2015-01-01 22:09:00 9
2 2015-01-01 01:05:00 2015-01-01 01:20:00 0 2015-01-01 01:05:00 2015-01-01 02:05:00 2015-01-01 01:00:00 2015-01-01 02:00:00 2015-01-01 01:05:00 2015-01-01 01:20:00 15
3 2015-01-01 11:05:00 2015-01-01 13:09:00 0 2015-01-01 11:05:00 2015-01-01 12:05:00 2015-01-01 11:00:00 2015-01-01 12:00:00 2015-01-01 11:05:00 2015-01-01 12:00:00 55
3 2015-01-01 11:05:00 2015-01-01 13:09:00 1 2015-01-01 12:05:00 2015-01-01 13:05:00 2015-01-01 12:00:00 2015-01-01 13:00:00 2015-01-01 12:00:00 2015-01-01 13:00:00 60
3 2015-01-01 11:05:00 2015-01-01 13:09:00 2 2015-01-01 13:05:00 2015-01-01 14:05:00 2015-01-01 13:00:00 2015-01-01 14:00:00 2015-01-01 13:00:00 2015-01-01 13:09:00 9
4 2015-01-01 15:05:00 2015-01-01 17:50:00 0 2015-01-01 15:05:00 2015-01-01 16:05:00 2015-01-01 15:00:00 2015-01-01 16:00:00 2015-01-01 15:05:00 2015-01-01 16:00:00 55
4 2015-01-01 15:05:00 2015-01-01 17:50:00 1 2015-01-01 16:05:00 2015-01-01 17:05:00 2015-01-01 16:00:00 2015-01-01 17:00:00 2015-01-01 16:00:00 2015-01-01 17:00:00 60
4 2015-01-01 15:05:00 2015-01-01 17:50:00 2 2015-01-01 17:05:00 2015-01-01 18:05:00 2015-01-01 17:00:00 2015-01-01 18:00:00 2015-01-01 17:00:00 2015-01-01 17:50:00 50
5 2015-01-01 16:30:00 2015-01-01 17:20:00 0 2015-01-01 16:30:00 2015-01-01 17:30:00 2015-01-01 16:00:00 2015-01-01 17:00:00 2015-01-01 16:30:00 2015-01-01 17:00:00 30
5 2015-01-01 16:30:00 2015-01-01 17:20:00 1 2015-01-01 17:30:00 2015-01-01 18:30:00 2015-01-01 17:00:00 2015-01-01 18:00:00 2015-01-01 17:00:00 2015-01-01 17:20:00 20
Final query
Finally, I sum the minutes grouping by an hour:
SELECT
HourStartFinal
,SUM(DATEDIFF(minute, MaxStart, MinEnd)) AS SumMinutesPerHour
FROM
#Durations AS D
CROSS APPLY
(
SELECT N.Number
FROM #Numbers AS N
WHERE N.Number <= DATEDIFF(hour, StartTime, EndTime)
) AS CA_Number
CROSS APPLY
(
SELECT
DATEADD(hour, CA_Number.Number, StartTime) AS HourStart
,DATEADD(hour, CA_Number.Number+1, StartTime) AS HourEnd
) AS CA_HourEnd
CROSS APPLY
(
-- Truncate to 1 hour.
SELECT
DATEADD(hour, DATEDIFF(hour, #VarStart, HourStart), #VarStart) AS HourStartFinal
,DATEADD(hour, DATEDIFF(hour, #VarStart, HourEnd), #VarStart) AS HourEndFinal
) AS CA_HourEndFinal
-- Intersect intervals [StartTime, EndTime] with [HourStartFinal, HourEndFinal]
CROSS APPLY
(
SELECT
CASE WHEN StartTime > HourStartFinal THEN StartTime ELSE HourStartFinal END AS MaxStart
,CASE WHEN EndTime < HourEndFinal THEN EndTime ELSE HourEndFinal END AS MinEnd
) AS CA_Intersect
GROUP BY HourStartFinal
ORDER BY HourStartFinal;
Final result set
HourStartFinal SumMinutesPerHour
2015-01-01 01:00:00.000 15
2015-01-01 11:00:00.000 55
2015-01-01 12:00:00.000 60
2015-01-01 13:00:00.000 9
2015-01-01 15:00:00.000 55
2015-01-01 16:00:00.000 90
2015-01-01 17:00:00.000 70
2015-01-01 21:00:00.000 55
2015-01-01 22:00:00.000 9
SQLFiddle

While Vladimir Baranov's answer is correct, It uses way to many CROSS APPLY.
Another way to get the minutes by hour, can be using the fact that in a range of starttime and endtime, except for the first hour and the last all other hours will have minutediff of the hour as 60.
We can use this and construct our logic, Something like this.
DECLARE #UserTask TABLE (ID int IDENTITY(1,1),UserID INT,TaskID INT, StartTime datetime, EndTime datetime);
INSERT INTO #UserTask VALUES
(1,1,'2015-01-01 21:05:00', '2015-01-01 22:09:00'),
(1,1,'2015-01-01 01:05:00', '2015-01-01 01:20:00'),
(1,1,'2015-01-01 11:05:00', '2015-01-01 13:09:00'),
(1,1,'2015-01-01 15:05:00', '2015-01-01 17:50:00'),
(1,1,'2015-01-01 16:30:00', '2015-01-01 17:20:00'),
(2,2,'2015-01-01 21:05:00', '2015-01-01 22:09:00');
;WITH CTENum AS
(
SELECT 1 rn UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), CTEHours as
(
SELECT TOP 24 ROW_NUMBER()OVER(ORDER BY c1.rn) - 1 rn FROM CTENum c1 CROSS JOIN CTENum c2
)
SELECT ID,UserID,TaskID,StartTime,EndTime,rn as DayHour,
CASE WHEN r_asc = 1 AND r_desc = 1 THEN DATEDIFF(minute,StartTime,EndTime)
WHEN r_asc = 1 THEN 60 - DATEPART(minute,StartTime)
WHEN r_desc = 1 THEN DATEPART(minute,EndTime)
ELSE 60 END MinuteTime
FROM #UserTask
CROSS APPLY(
SELECT *,ROW_NUMBER()OVER(ORDER BY rn ASC) r_asc,ROW_NUMBER()OVER(ORDER BY rn DESC) r_desc
FROM CTEHours C
WHERE C.rn BETWEEN DATEDIFF(hour,CONVERT(VARCHAR(10),StartTime,112),StartTime) AND DATEDIFF(hour,CONVERT(VARCHAR(10),StartTime,112),EndTime)
) N
ORDER BY ID,DayHour

You might want to look into the datepart() function, it'll help you manipulate your dates more cleanly. For example:
select #endOfHour = dateadd(hour,
1,
datetimefromparts(
datepart(year, #startTime),
datepart(month, #startTime),
datepart(day, #startTime),
datepart(hour, #startTime),
0,
0,
0));
select h.theHour, #startTime, #endOfHour, datediff(minute, #startTime, #endOfHour)
from ListOfHours as h
where datepart(hour, #startTime) = h.Hour;

Related

Order by Descending and continue with the same set of group

I want records in descending order of DATE and continue with the same set of group i.e. here the MAX date is 2018-10-25 00:00:00.000 then the next 3 records should be of REC = 5
REC DATE
===========================
1 2018-01-02 00:00:00.000
1 2018-01-03 00:00:00.000
1 2018-01-04 00:00:00.000
2 2018-06-01 00:00:00.000
2 2018-06-02 00:00:00.000
3 2018-03-01 00:00:00.000
3 2018-05-02 00:00:00.000
3 2018-01-03 00:00:00.000
3 2018-08-04 00:00:00.000
3 2018-10-05 00:00:00.000
4 2018-10-06 00:00:00.000
5 2018-10-25 00:00:00.000
5 2018-05-03 00:00:00.000
5 2018-09-09 00:00:00.000
This is what I have tried but no success.
SELECT t1.REC, t1.DATE
FROM TEMP AS t1
INNER JOIN (SELECT REC, MAX(DATE) AS MaxDate
FROM TEMP
GROUP BY REC) AS t2
ON (t1.REC = t2.REC AND t1.DATE = t2.MaxDate)
Expected result should be something like this:
REC DATE
===============================
5 2018-10-25 00:00:00.000
..........{Remaining dates of `REC` 5}
4 2018-10-06 00:00:00.000
..........{Remaining dates of `REC` 4}
3 2018-10-05 00:00:00.000
..........{Remaining dates of `REC` 3}
2 2018-06-02 00:00:00.000
..........{Remaining dates of `REC` 2}
1 2018-01-04 00:00:00.000
..........{Remaining dates of `REC` 1}
max_date is maximum date per REC
SELECT *, max_date = MAX(DATE) OVER (PARTITION BY REC)
FROM yourtable
ORDER BY max_date DESC, DATE DESC

update multiple rows with random datetime sql server

I have table sql server 2005 that contains 3000 rows Like that
<<ID>> <<Time>>
5620298 2015-01-05 16:00:00.000
5620299 2015-01-06 16:00:00.000
5620300 2015-01-07 16:00:00.000
5620301 2015-01-08 16:00:00.000
5620302 2015-01-09 16:00:00.000
5620303 2015-01-10 16:00:00.000
5620304 2015-01-11 16:00:00.000
5620305 2015-01-12 16:00:00.000
5620306 2015-01-13 16:00:00.000
i wanna to change time with random minutes between 1 to 10 minutes
<<ID>> <<Time>>
5620298 2015-01-05 16:02:00.000
5620299 2015-01-06 16:05:00.000
5620300 2015-01-07 16:01:00.000
5620301 2015-01-08 16:00:00.000
5620302 2015-01-09 16:02:00.000
5620303 2015-01-10 16:07:00.000
5620304 2015-01-11 16:06:00.000
5620305 2015-01-12 16:09:00.000
5620306 2015-01-13 16:00:00.000
How can I do this?
Thanks!
You could:
UPDATE TBL
SET [TIME] = DATEADD(MINUTE, ABS(CHECKSUM(NEWID()) % 10) + 1, [TIME])
Not very efficient but presumably this is just for testing.
You can try RAND()
UPDATE TBL
SET [TIME] = DATEADD(MINUTE, ABS(ROUND(RAND()*10,0)) , [TIME])
You may get duplicate random numbers, agree with Ale; we can use NEWID() instead.

How to update record based on value of next record in SQL Server 2008

I like to update a column based on a value of the next record:
resid startdate enddate weekday hours
-----------------------------------------------
2980 2013-09-23 2014-12-31 1 6
2980 2013-09-23 2014-12-31 2 6
2980 2013-09-23 2014-12-31 3 6
2980 2013-09-23 2014-12-31 4 6
2980 2013-09-23 2014-12-31 5 6
2980 2015-01-01 NULL 1 6,8
2980 2015-01-01 NULL 2 6,8
2980 2015-01-01 NULL 3 6,8
2980 2015-01-01 NULL 4 6,8
2980 2015-01-01 NULL 5 6,8
2980 2015-07-01 NULL 1 6
2980 2015-07-01 NULL 2 6
2980 2015-07-01 NULL 3 6
2980 2015-07-01 NULL 4 6
2980 2015-07-01 NULL 5 6
I like to update the NULL value in column enddate. It needs to get a value of the next startdate - 1 day.
For instance, for all records with startdate 2015-01-01, the column enddate needs to be updated with 2015-07-01 - 1 day.
Is there someone who has a solution?
update TableName set enddate = dateadd(day,1,startdate)
One way to do it is with a subquery:
UPDATE t1
SET enddate = (SELECT TOP 1 DATEADD(DAY, -1, startdate)
FROM YourTable t2
WHERE t1.startdate < t2.startdate
ORDER BY t2.startdate)
FROM YourTable t1
WHERE t1.enddate is null

Query to get items due in the next 7 days

I have an insurance_end column in my table, which is a datetime value.
So with today's date being: 2015-02-20, I want to retrieve items that are due to end in the next 7 days.
Sample Data:
insurance_end
=======================
2017-02-13 00:00:00.000
2016-02-13 00:00:00.000
2015-02-13 00:00:00.000
2015-02-14 00:00:00.000
2015-02-20 00:00:00.000
2015-02-28 00:00:00.000
2015-02-28 00:00:00.000
2015-02-04 00:00:00.000
2015-02-13 00:00:00.000
2015-02-01 00:00:00.000
2015-02-10 00:00:00.000
2013-02-09 00:00:00.000
Desired output would be:
insurance_end
=======================
2015-02-14 00:00:00.000
2015-02-20 00:00:00.000
2015-02-13 00:00:00.000
Here's what I tried:
SELECT*
FROM customer_profile
WHERE DATEADD(dd, -7, insurance_end) <= CAST(insurance_end AS DATETIME)
As I understand it, you want to show records where the insurance is ending within the next 7 days.
Just use GETDATE() to get today's date and subtract 7 days to get the date of 7 days prior. CONVERT to DATE to take off the time portion.
SELECT CONVERT(DATE, GETDATE()) AS TodaysDate,
CONVERT(DATE, GETDATE() - 7) AS TodayMinus7
This will give you:
TodaysDate TodayMinus7
==========================
2015-02-20 2015-02-13
You can then compare this value to your insurance_end values:
SQL Fiddle Demo
MS SQL Server Schema Setup:
CREATE TABLE customer_profile
([insurance_end] datetime)
;
INSERT INTO customer_profile
([insurance_end])
VALUES
('2015-02-13 00:00:00'),
('2015-02-14 00:00:00'),
('2015-02-20 00:00:00'),
('2015-02-28 00:00:00'),
('2015-02-28 00:00:00'),
('2015-02-04 00:00:00'),
('2015-02-13 00:00:00'),
('2015-02-01 00:00:00'),
('2015-02-10 00:00:00'),
('2013-02-09 00:00:00')
;
Query To Get Desired Output:
SELECT *
FROM customer_profile
WHERE CONVERT(DATE, GETDATE() -7) <= insurance_end
AND insurance_end <= CONVERT(DATE, GETDATE())
You could also change the WHERE clause to use BETWEEN:
WHERE insurance_end BETWEEN
CONVERT(DATE, GETDATE() -7) AND CONVERT(DATE, GETDATE())
Results:
| INSURANCE_END |
|---------------------------------|
| February, 13 2015 00:00:00+0000 |
| February, 14 2015 00:00:00+0000 |
| February, 20 2015 00:00:00+0000 |
| February, 13 2015 00:00:00+0000 |
I hope this is what you are looking for.
Query
SELECT *
FROM insurance
WHERE
DATEDIFF(day,GETDATE(),insurance_end)=-7;
Fiddle demo for reference

How to compare time slot in SQL Server?

I have a table [pricelist]
startHour
endHour
Price
and another table that contains the [actualuse]
startDate
endDate
user
My data
pricelist:
startHour | endHour | price
----------------------------
00:00 | 07:59 | 10
08:00 | 15:59 | 20
16:00 | 23:59 | 5
actualUse:
startDate | endDate | jobId
-------------------------------------------
12/10/2014 08:30 | 12/10/2014 15:20| 1
12/10/2014 07:30 | 12/10/2014 18:20| 2
12/10/2014 07:30 | 13/10/2014 16:20| 3
12/10/2014 09:30 | 13/10/2014 00:20| 4
I try to get for every gob all rows in pricelist the are belong to. For example for jobId 1 I will get
startDate | endDate | jobId |price
---------------------------------------------------
12/10/2014 08:30 | 12/10/2014 15:20| 1 |20
for jobId 2
startDate | endDate | jobId |price
---------------------------------------------------
12/10/2014 07:30 | 12/10/2014 07:59| 2 |10
12/10/2014 08:00 | 12/10/2014 15:59| 2 |20
12/10/2014 16:00 | 12/10/2014 18:20| 2 |5
for jobId 3
startDate | endDate | jobId |price
---------------------------------------------------
12/10/2014 07:30 | 12/10/2014 07:59| 3 |10
12/10/2014 08:00 | 12/10/2014 15:59| 3 |20
12/10/2014 16:00 | 12/10/2014 23:59| 3 |5
13/10/2014 00:00 | 13/10/2014 07:59| 3 |10
13/10/2014 08:00 | 13/10/2014 15:59| 3 |20
13/10/2014 16:00 | 13/10/2014 16:20| 3 |5
Here is a possible working solution. I know the cursor is a bit ugly but I had to create another table with every possibles dates between the date ranges. You might be able to refactor some date computation too (I assumed you were working with TIME datatype)
/*
create table pricelist
(
startHour time,
endHour time,
price decimal(18,2)
)
create table actualuse
(
startDate datetime,
endDate datetime,
jobId int
)
insert pricelist values
('00:00','07:59',10),
('08:00','15:59',20),
('16:00','23:59',5)
set dateformat dmy
insert actualuse values
('12/10/2014 08:30','12/10/2014 15:20',1),
('12/10/2014 07:30','12/10/2014 18:20',2),
('12/10/2014 07:30','13/10/2014 16:20',3),
('12/10/2014 09:30','13/10/2014 00:20',4)
*/
BEGIN TRY DROP TABLE #actualUseDays END TRY
BEGIN CATCH END CATCH
CREATE TABLE #actualUseDays (
startDate DATETIME
,endDate DATETIME
,jobId INT
)
DECLARE #startDate DATETIME
,#endDate DATETIME
,#jobId INT;
DECLARE cur CURSOR FORWARD_ONLY FOR SELECT * FROM actualuse
OPEN cur;
FETCH NEXT FROM cur INTO #startDate ,#endDate ,#jobId
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT #actualUseDays
SELECT #startDate
,iif(CAST(#endDate AS DATE) <> CAST(#startDate AS DATE), DATEADD(day, DATEDIFF(day, '19000101', cast(#startDate AS DATE)), CAST(CAST('23:59:59' AS TIME) AS
DATETIME2(7))), #endDate)
,#jobId
UNION
SELECT CAST(DATEADD(DAY, number + 1, #startDate) AS DATE) [Date]
,iif(CAST(#endDate AS DATE) <> CAST(DATEADD(DAY, number + 1, #startDate) AS DATE), DATEADD(day, DATEDIFF(day, '19000101', CAST(DATEADD(DAY, number + 1,
#startDate) AS DATE)), CAST(CAST('23:59:59' AS TIME) AS DATETIME2(7))), #endDate)
,#jobId
FROM master..spt_values
WHERE type = 'P'
AND DATEADD(DAY, number + 1, CAST(#startDate AS DATE)) < #endDate
FETCH NEXT FROM cur INTO #startDate ,#endDate ,#jobId
END
CLOSE cur;
DEALLOCATE cur;
/*
#actualUseDays now contains :
startDate endDate jobId
----------------------- ----------------------- -----------
2014-10-12 08:30:00.000 2014-10-12 15:20:00.000 1
2014-10-12 07:30:00.000 2014-10-12 18:20:00.000 2
2014-10-12 07:30:00.000 2014-10-12 23:59:59.000 3
2014-10-13 00:00:00.000 2014-10-13 16:20:00.000 3
2014-10-12 09:30:00.000 2014-10-12 23:59:59.000 4
2014-10-13 00:00:00.000 2014-10-13 00:20:00.000 4
*/
SELECT iif(CAST(a.startDate AS TIME) > p.startHour, startDate, DATEADD(day, DATEDIFF(day, '19000101', CAST(startDate AS DATE)), CAST(startHour AS DATETIME2(7)))) AS
startDate
,iif(CAST(a.endDate AS TIME) < p.endHour, endDate, DATEADD(day, DATEDIFF(day, '19000101', CAST(endDate AS DATE)), CAST(endHour AS DATETIME2(7)))) AS endDate
,jobId
,price
FROM #actualUseDays a
INNER JOIN pricelist p
ON CAST(a.startDate AS TIME) <= p.endHour
AND CAST(a.endDate AS TIME) >= p.startHour
ORDER BY jobId
,iif(CAST(a.startDate AS TIME) > p.startHour, startDate, DATEADD(day, DATEDIFF(day, '19000101', CAST(startDate AS DATE)), CAST(startHour AS DATETIME2(7))))
Results :
startDate endDate jobId price
--------------------------- --------------------------- ----------- ---------------------------------------
2014-10-12 08:30:00.0000000 2014-10-12 15:20:00.0000000 1 20.00
2014-10-12 07:30:00.0000000 2014-10-12 07:59:00.0000000 2 10.00
2014-10-12 08:00:00.0000000 2014-10-12 15:59:00.0000000 2 20.00
2014-10-12 16:00:00.0000000 2014-10-12 18:20:00.0000000 2 5.00
2014-10-12 07:30:00.0000000 2014-10-12 07:59:00.0000000 3 10.00
2014-10-12 08:00:00.0000000 2014-10-12 15:59:00.0000000 3 20.00
2014-10-12 16:00:00.0000000 2014-10-12 23:59:00.0000000 3 5.00
2014-10-13 00:00:00.0000000 2014-10-13 07:59:00.0000000 3 10.00
2014-10-13 08:00:00.0000000 2014-10-13 15:59:00.0000000 3 20.00
2014-10-13 16:00:00.0000000 2014-10-13 16:20:00.0000000 3 5.00
2014-10-12 09:30:00.0000000 2014-10-12 15:59:00.0000000 4 20.00
2014-10-12 16:00:00.0000000 2014-10-12 23:59:00.0000000 4 5.00
2014-10-13 00:00:00.0000000 2014-10-13 00:20:00.0000000 4 10.00

Resources