I have a table with this entries:
StartDate | EndDate
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-06 | 2016-01-16
2016-01-07 | 2016-01-17
2016-01-07 | 2016-01-17
2016-01-07 | 2016-01-17
2016-01-07 | 2016-01-17
2016-01-07 | 2016-01-17
2016-01-07 | 2016-01-17
2016-01-07 | 2016-01-17
2016-01-07 | 2016-01-17
2016-01-08 | 2016-01-18
2016-01-08 | 2016-01-18
2017-01-01 | 2017-01-10
2026-01-06 | 2026-01-16
2026-01-07 | 2026-01-17
And my query in stored procedure is:
SELECT ROW_NUMBER() OVER ( ORDER BY [StartDate] ASC) as ROWNUM, [Oid]
From [dbo].[Ument]
Where (
(#StartDate is null or StartDate >= #StartDate)
or (#EndDate is null or EndDate <= #EndDate)
)
I want to search by #StartDate written by user or, if is null/empty, by #StartDate >= today's date.
But, at the same time, I want to search by #endDate, written by user or, if is null/empty, EndDate >= today's.
If today's is between two dates, i need to return it.
Like this:
#startDate isn't null?
YES: use the #startDate written by user to filter startDate >= #StartDate.
NO: use today's date to put startDate >= today.
#endDate isn't null?
YES: use the #endDate written by user to filter endDate <= #endDate
NO: use max-date (e.g.: 2050/12/31) to filter endDate <= max-Date
Is this what you want?
WHERE startDate >= COALESCE(#StartDate, GETDATE()) AND
endDate <= COALESCE(#EndDate, GETDATE())
You may want this logic, but with the current date with no time:
WHERE startDate >= COALESCE(#StartDate, CAST(GETDATE() AS DATE)) AND
endDate <= COALESCE(#EndDate, CAST(GETDATE() AS DATE))
After the comment, diabolickman's question and Gordon's answer can be mixed like:
SELECT ROW_NUMBER() OVER ( ORDER BY [StartDate] ASC) as ROWNUM, [Oid]
From [dbo].[Ument]
Where (
StartDate >= ISNULL(#StartDate, CAST(GETDATE() AS DATE))
AND (#EndDate is null or EndDate <= #EndDate)
)
This way, End date is ignored if it's null, so you dont need to compare it against max date.
Changed middle OR to AND, assuming user wants to filter a date range.
I used ISNULL instead of COALESCE, just to show another alternative.
I think my problem is solved! :)
I change the last solution to this and the query returns what I want!
SELECT ROW_NUMBER() OVER ( ORDER BY [StartDate] ASC) as ROWNUM, [Oid] From [dbo].[Ument]
Where (
StartDate >= ISNULL(#StartDate, CAST(GETDATE() AS DATE))
and EndDate <= ISNULL(#EndDate, CAST('20501231' AS DATE))
)
Thanks for the help ramazan's and Gordon's. :)
Related
Let's say I have two tables:
Salary:
PersonId, StartDate, EndDate, Salary
Title:
PersonId, StartDate, EndDate, Title
The salary of a person is independent of his title, either may change at any time.
How can I best get all the consecutive StartDate/EndDate time intervals during which salary and title don't change?
So this...
Salary
Me | 2017-01-01 | 2017-01-31 | 2000
Me | 2017-02-01 | 2017-05-31 | 2100
Me | 2017-06-01 | 2017-07-31 | 2300
Title
Me | 2017-01-01 | 2017-03-31 | Junior
Me | 2017-04-01 | 2017-07-31 | Senior
would return:
SalaryAndTitle
Me | 2017-01-01 | 2017-01-31 | 2000 | Junior
Me | 2017-02-01 | 2017-03-31 | 2100 | Junior
Me | 2017-04-01 | 2017-05-31 | 2100 | Senior
Me | 2017-06-01 | 2017-07-31 | 2300 | Senior
This is a simplified example. In my real case there would be many changing columns, and the resulting data set should still contain time intervals where those columns have unchanged values with respect to that time period.
I'm thinking about over( partition by...) but I can't get it to work. Any help appreciated.
Cheers,
Kim
I dont know the performance requirements you have and i am sure there will be better ways of doing this, however....
one sort of catch all solution to these problems is to break it down day by day and then use standard aggregate functions, for example below I am assuming you have a table called dates that has all the dates you are interested in:
select
p.personid
,min(ds.dt) as from
,max(ds.dt) as to
,s.salary
,t.title
from
dates as ds
cross join
(select distinct personid from salary) as p
left outer join salary as s
on ds.dt >= s.startdate
and ds.dt <= s.enddate
and p.personid = s.personid
left outer join title as t
on ds.dt >= t.startdate
and ds.dt <= t.enddate
and p.personid = t.personid
group by
p.personid
,s.salary
,t.title
I am using left outer joins here as i would start with that and do some analysis of the data.
I use this type of thing for analysis, reporting and data migration a lot. I have used it for billing calculations too - however I have done absolutely no performance testing on this type of approach. the focus has been writing queries that are easy to maintain and have all the power you could ever want (analysis tends to be easyier with highly de-normalised data like a day by day breakdown)
I added some records to the sample data to address the issue raised surrounding the possibility of a PersonID having more than one time range where the PersonID has the same Title and Salary.
Answer:
create table dbo.Salary
(
PersonID varchar(3)
, StartDate date
, EndDate date
, Salary int
)
create table dbo.Title
(
PersonID varchar(3)
, StartDate date
, EndDate date
, Title varchar(10)
)
insert into dbo.Salary
values ('Me', '2017-01-01', '2017-01-31', 2000)
, ('Me', '2017-02-01', '2017-05-31', 2100)
, ('Me', '2017-06-01', '2017-07-31', 2300)
, ('You', '2017-01-01', '2017-03-31', 2400)
, ('You', '2017-04-01', '2017-08-31', 2500)
, ('You', '2017-09-01', '2017-12-31', 2400)
insert into dbo.Title
values ('Me', '2017-01-01', '2017-03-31', 'Junior')
, ('Me', '2017-04-01', '2017-07-31', 'Senior')
, ('You', '2017-01-01', '2017-02-28', 'Junior')
, ('You', '2017-03-01', '2017-05-31', 'Senior')
, ('You', '2017-06-01', '2017-12-31', 'Junior')
select a.PersonID
, a.StartDate
, a.EndDate
, a.Salary
, a.Title
from (
select s.PersonID
, iif(s.StartDate < t.StartDate, t.StartDate, s.StartDate) as StartDate
, iif(s.EndDate < t.EndDate, s.EndDate, t.EndDate) as EndDate
, s.Salary
, t.Title
from dbo.Salary as s
inner join dbo.Title as t on s.PersonID = t.PersonID
) as a
where 1=1
and datediff(d, a.StartDate, a.EndDate) >= 0 --is it a valid time range?
The sub-query duplicates all possible StartDate / EndDate combinations for a PersonID, and the outer query determines if that time range is valid.
Output:
PersonID StartDate EndDate Salary Title
Me 2017-01-01 2017-01-31 2000 Junior
Me 2017-02-01 2017-03-31 2100 Junior
Me 2017-04-01 2017-05-31 2100 Senior
Me 2017-06-01 2017-07-31 2300 Senior
You 2017-01-01 2017-02-28 2400 Junior
You 2017-03-01 2017-03-31 2400 Senior
You 2017-04-01 2017-05-31 2500 Senior
You 2017-06-01 2017-08-31 2500 Junior
You 2017-09-01 2017-12-31 2400 Junior
I currently have the following table:
+-----+-----------------------------+------------------------------+
| ID | StartDate | EndDate |
+-----+-----------------------------+------------------------------|
| 1 | 2017-07-24 08:00:00.000 | 2017-07-29 08:00:00.000 |
| 2 | 2017-07-25 08:00:00.000 | 2017-07-28 08:00:00.000 |
| 3 | 2017-07-25 08:00:00.000 | 2017-07-26 08:00:00.000 |
+-----+-----------------------------+------------------------------+
I would like to know the count of the ID's that were not Closed on each date.
So for example, I wan't to know the count of open ID's on 2017-07-26 00:00:00.000. This would be all 3 in this case.
Another example: I wan't to know the count of open ID's on 2017-07-29 00:00:00.000. Which would be result to 1. Only ID=1 is Not yet closed at that date.
I have tried using another solution here on StackOverflow, but I can't quite figure why it is giving me false results.
declare #dt date, #dtEnd date
set #dt = getdate()-7
set #dtEnd = dateadd(day, 100, #dt);
WITH CTEt1 (SupportCallID, StartDate, EndDate, Onhold)
as
(SELECT SupportCallID
,OpenDate
,MAX(CASE WHEN StatusID IN('19381771-8E81-40C5-8E36-62A7DB0A2A99', '95C7A5FB-2389-4D14-9DAE-A08BFCC3B09A', 'D5429790-3B43-4462-9E1E-2466EA29AC74') then CONVERT(DATE, LastChangeDate) end) EndDate
,OnHold
FROM [ClienteleITSM_Prod_Application].[dbo].[SupportCall]
group by SupportCallID, OpenDate, OnHold
)
SELECT dates.myDate,
(SELECT COUNT(*)
FROM CTEt1
WHERE myDate BETWEEN StartDate and EndDate
)
FROM
(select dateadd(day, number, #dt) mydate
from
(select distinct number from master.dbo.spt_values
where name is null
) n
where dateadd(day, number, #dt) < #dtEnd) dates
If you use a cte to create a table of dates that span the range of dates in your source table, you can easily left join from that to your source table and count up the rows returned:
declare #t table(ID int,StartDate datetime,EndDate datetime);
insert into #t values (1,'2017-07-24 08:00:00.000','2017-07-29 08:00:00.000'),(2,'2017-07-25 08:00:00.000','2017-07-28 08:00:00.000'),(3,'2017-07-25 08:00:00.000','2017-07-26 08:00:00.000');
declare #StartDate datetime = (select min(StartDate) from #t);
declare #EndDate datetime = (select max(EndDate) from #t);
-- Table with 10 rows in to be joined together to create a large tally table (10 * 10 * 10 * etc)
with t(t) as (select t from (values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(t))
-- Add the row_number of the tally table to your start date to generate all dates within your data range
,d(d) as (select top(datediff(d,#StartDate,#EndDate)+1) dateadd(d,row_number() over (order by (select null))-1,#StartDate) from t t1,t t2,t t3)
select d.d
,count(t.ID) as OpenIDs
from d
left join #t as t
on(d.d between cast(t.StartDate as date) and t.EndDate)
group by d.d
order by d.d;
Output:
+-------------------------+---------+
| d | OpenIDs |
+-------------------------+---------+
| 2017-07-24 08:00:00.000 | 1 |
| 2017-07-25 08:00:00.000 | 3 |
| 2017-07-26 08:00:00.000 | 3 |
| 2017-07-27 08:00:00.000 | 2 |
| 2017-07-28 08:00:00.000 | 2 |
| 2017-07-29 08:00:00.000 | 1 |
+-------------------------+---------+
Using T-SQL, I want a new column that will show me the first day of each month, for the current year of getdate().
After that I need to count the rows on this specific date. Should I do it with CTE or a temp table?
If 2012+, you can use DateFromParts()
To Get a List of Dates
Select D = DateFromParts(Year(GetDate()),N,1)
From (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) N(N)
Returns
D
2017-01-01
2017-02-01
2017-03-01
2017-04-01
2017-05-01
2017-06-01
2017-07-01
2017-08-01
2017-09-01
2017-10-01
2017-11-01
2017-12-01
Edit For Trans Count
To get Transactions (assuming by month). It becomes a small matter of a left join to created Dates
-- This is Just a Sample Table Variable for Demonstration.
-- Remove this and Use your actual Transaction Table
--------------------------------------------------------------
Declare #Transactions table (TransDate date,MoreFields int)
Insert Into #Transactions values
('2017-02-18',6)
,('2017-02-19',9)
,('2017-03-05',5)
Select TransMonth = A.MthBeg
,TransCount = count(B.TransDate)
From (
Select MthBeg = DateFromParts(Year(GetDate()),N,1)
,MthEnd = EOMonth(DateFromParts(Year(GetDate()),N,1))
From (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) N(N)
) A
Left Join #Transactions B on TransDate between MthBeg and MthEnd
Group By A.MthBeg
Returns
TransMonth TransCount
2017-01-01 0
2017-02-01 2
2017-03-01 1
2017-04-01 0
2017-05-01 0
2017-06-01 0
2017-07-01 0
2017-08-01 0
2017-09-01 0
2017-10-01 0
2017-11-01 0
2017-12-01 0
For an adhoc table of months for a given year:
declare #year date = dateadd(year,datediff(year,0,getdate() ),0)
;with Months as (
select
MonthStart=dateadd(month,n,#year)
from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11)) t(n)
)
select MonthStart
from Months
rextester demo: http://rextester.com/POKPM51023
returns:
+------------+
| MonthStart |
+------------+
| 2017-01-01 |
| 2017-02-01 |
| 2017-03-01 |
| 2017-04-01 |
| 2017-05-01 |
| 2017-06-01 |
| 2017-07-01 |
| 2017-08-01 |
| 2017-09-01 |
| 2017-10-01 |
| 2017-11-01 |
| 2017-12-01 |
+------------+
The first part: dateadd(year,datediff(year,0,getdate() ),0) adds the number of years since 1900-01-01 to the date 1900-01-01. So it will return the first date of the year. You can also swap year for other levels of truncation: year, quarter, month, day, hour, minute, second, et cetera.
The second part uses a common table expression and the table value constructor (values (...),(...)) to source numbers 0-11, which are added as months to the start of the year.
Not sure why you require recursive... But for first day of month you can try query like below:
Select Dateadd(day,1,eomonth(Dateadd(month, -1,getdate())))
declare #year date = dateadd(year,datediff(year,0,getdate() ),0)
;WITH months(MonthNumber) AS
(
SELECT 0
UNION ALL
SELECT MonthNumber+1
FROM months
WHERE MonthNumber < 11
)
select dateadd(month,MonthNumber,#year)
from months
I have the following results
Date | EmployeeID
2015-11-18 | 1
2015-11-18 | 1
2015-11-18 | 1
2015-11-19 | 1
2015-11-19 | 1
2015-11-20 | 1
2015-11-20 | 1
2015-11-20 | 1
2015-11-25 | 1
But given a range of dates (2015-11-15 - 2015-11-30) I want to display something like this
Date | NbEmployees
2015-11-15 | 0
2015-11-16 | 0
2015-11-17 | 0
2015-11-18 | 3
2015-11-19 | 2
2015-11-20 | 3
2015-11-21 | 0
2015-11-22 | 0
2015-11-23 | 0
2015-11-24 | 0
2015-11-25 | 1
2015-11-26 | 0
2015-11-27 | 0
2015-11-28 | 0
2015-11-29 | 0
2015-11-30 | 0
I've using this approach by I only get the values from the table with data
DECLARE #StartDate DATE = '2015-11-15 00:00:00', #EndDate DATE = '2015-11-30 23:59:00'
DECLARE #CurrentDate DATE = #StartDate
DECLARE #DateRange TABLE (CurrentDate DATETIME)
WHILE(#CurrentDate <= #EndDate)
BEGIN
INSERT INTO #DateRange VALUES(#CurrentDate)
SET #CurrentDate = DATEADD(DAY, 1, #CurrentDate)
END
SELECT r.CurrentDate, COUNT(EmployeeID)
FROM Employee e
RIGHT JOIN #DateRange r ON e.HireDate = r.Date
Results:
Date | NbEmployees
2015-11-18 | 3
2015-11-19 | 2
2015-11-20 | 3
2015-11-25 | 1
Try it like this
DECLARE #tbl TABLE([Date] DATE, EmployeeID INT);
INSERT INTO #tbl VALUES
('2015-11-18',1)
,('2015-11-18',1)
,('2015-11-18',1)
,('2015-11-19',1)
,('2015-11-19',1)
,('2015-11-20',1)
,('2015-11-20',1)
,('2015-11-20',1)
,('2015-11-25',1);
DECLARE #StartDate DATE = '2015-11-15 00:00:00', #EndDate DATE = '2015-11-30 23:59:00'
DECLARE #CurrentDate DATE = #StartDate
DECLARE #DateRange TABLE (CurrentDate DATETIME)
WHILE(#CurrentDate <= #EndDate)
BEGIN
INSERT INTO #DateRange VALUES(#CurrentDate)
SET #CurrentDate = DATEADD(DAY, 1, #CurrentDate)
END
SELECT CurrentDate,ISNULL(NbEmployees,0) AS NbEmployees
FROM #DateRange
LEFT JOIN
(
SELECT COUNT(tbl.EmployeeID) AS NbEmployees
,tbl.[Date] AS Date
FROM #tbl AS tbl
GROUP BY tbl.[Date]
) AS grouped ON CurrentDate=grouped.[Date]
The result
2015-11-15 00:00:00.000 0
2015-11-16 00:00:00.000 0
2015-11-17 00:00:00.000 0
2015-11-18 00:00:00.000 3
2015-11-19 00:00:00.000 2
2015-11-20 00:00:00.000 3
2015-11-21 00:00:00.000 0
2015-11-22 00:00:00.000 0
2015-11-23 00:00:00.000 0
2015-11-24 00:00:00.000 0
2015-11-25 00:00:00.000 1
2015-11-26 00:00:00.000 0
2015-11-27 00:00:00.000 0
2015-11-28 00:00:00.000 0
2015-11-29 00:00:00.000 0
2015-11-30 00:00:00.000 0
With something like this you could create your date-tally on the fly (avoid loops!!!)
DECLARE #StartDate DATE = '2015-11-15 00:00:00', #EndDate DATE = '2015-11-30 23:59:00';
WITH DayCount(Nmbr) AS
(
SELECT TOP (DATEDIFF(DAY,#StartDate,#EndDate)+1) ROW_NUMBER() OVER(ORDER BY (SELECT NULL))-1 FROM sys.objects
)
,RunningDates(CurrentDate) AS
(
SELECT DATEADD(DAY,Nmbr,#StartDate) FROM DayCount
)
SELECT * FROM RunningDates
This is bound to the max count of sys.objects... You'll find a lot of examples how to create running numbers on the fly or how to create a date-tally table (for example this: https://stackoverflow.com/a/32474751/5089204)
You don't need to create and maintain a list_of_dates table. You could just outter join to something like this:
For SqlServer:
SELECT
DATEADD(DAY,number,'20010101') [Date]
FROM
master..spt_values
WHERE
type = 'P'
AND DATEADD(DAY,number,'20010101') <= '20010104'
Or for Oracle, this:
select
rownum - 1 + to_date('01-JAN-2001', 'dd-mon-yyyy') dates
from
all_objects
where
rownum < to_date('01-FEB-2001', 'dd-mon-yyyy') - to_date('01-JAN-2001', 'dd-mon-yyyy') + 2
The output from this query looks like this:
DATES
---------
01-JAN-01
02-JAN-01
03-JAN-01
04-JAN-01
05-JAN-01
06-JAN-01
07-JAN-01
08-JAN-01
09-JAN-01
10-JAN-01
11-JAN-01
12-JAN-01
13-JAN-01
14-JAN-01
15-JAN-01
16-JAN-01
17-JAN-01
18-JAN-01
19-JAN-01
20-JAN-01
21-JAN-01
22-JAN-01
23-JAN-01
24-JAN-01
25-JAN-01
26-JAN-01
27-JAN-01
28-JAN-01
29-JAN-01
30-JAN-01
31-JAN-01
01-FEB-01
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