Join table on a date between two dates in the target table - sql-server

I have two tables
tbl_TimeEntries
EmployeeID int,
StartDateTime datetime,
EndDateTime datetime
tbl_Crew_Employees
CrewID,
EmployeeID,
StartDate,
EndDate
I also have a query that produces the number of hours worked per employee per day, but I also want to include the crew the employee was on for that day.
SELECT tbl_TimeEntries.EmployeeID,
SUM(DATEDIFF(SECOND, StartDateTime, EndDateTime) / 60.0
/ 60.0) as Hours,
CAST(StartDateTime AS date) as WorkDate
FROM tbl_TimeEntries
GROUP BY tbl_TimeEntries.EmployeeID, CAST(StartDateTime AS date)
ORDER BY CAST(StartDateTime AS date)
I'm not sure how to include the CrewID in this query because the tbl_Crew_Employees uses a StartDate and EndDate (meaning the employee was on this crew from StartDate to EndDate). I would either need to expand the StartDate/EndDate range or use some sort of SQL magic of which I am unaware.
Here is a sample of the data from the tbl_Crew_Employees, tbl_TimeEntries and the current query with the desired column data added. EmployeeID 88 is represented on two different crews in the sample.
CrewID EmployeeID StartDate EndDate
13 11 2013-03-30 2013-05-12
12 88 2013-01-02 2013-04-18
12 66 2013-01-02 2013-06-30
13 88 2013-04-19 2013-04-21
11 111 2013-01-02 2013-04-28
EmployeeID StartDateTime EndDateTime
11 2013-04-18 08:00 2013-04-18 12:00
11 2013-04-18 12:30 2013-04-18 18:30
111 2013-04-18 10:00 2013-04-18 12:00
111 2013-04-18 12:30 2013-04-18 18:30
88 2013-04-18 11:00 2013-04-18 12:00
88 2013-04-18 12:30 2013-04-18 19:30
66 2013-04-18 10:00 2013-04-18 12:00
66 2013-04-18 12:30 2013-04-18 18:30
11 2013-04-20 08:00 2013-04-20 12:00
11 2013-04-20 12:30 2013-04-20 18:00
111 2013-04-20 10:00 2013-04-20 12:00
111 2013-04-20 12:30 2013-04-20 18:30
88 2013-04-20 11:00 2013-04-20 12:00
88 2013-04-20 12:30 2013-04-20 19:30
66 2013-04-20 10:00 2013-04-20 12:00
66 2013-04-20 12:30 2013-04-20 17:00
EmployeeID Hours WorkDate CrewID(desired)
11 10.00 2013-04-18 13
88 8.00 2013-04-18 12
66 8.00 2013-04-18 12
111 8.00 2013-04-18 11
11 7.50 2013-04-20 13
88 8.00 2013-04-20 13
66 6.50 2013-04-20 12
111 8.00 2013-04-20 11

Try this:
SELECT
tbl_TimeEntries.employeeid
,SUM(DATEDIFF(SECOND, StartDateTime, EndDateTime) / 60.0 / 60.0) AS HOURS
,CAST(StartDateTime AS DATE) AS WorkDate
,tbl_Crew_Employees.crewid
FROM tbl_TimeEntries
INNER JOIN tbl_Crew_Employees ON tbl_timeentries.employeeid = tbl_Crew_Employees.employeeid
AND startdatetime >= startdate
AND enddatetime <= enddate
GROUP BY tbl_TimeEntries.employeeid
,tbl_Crew_Employees.crewid
,CAST(tbl_TimeEntries.StartDateTime AS DATE)
ORDER BY WorkDate

Should be a simple join.
declare #tbl_Crew_Employees table(CrewID int, EmployeeID int, StartDate date, EndDate date)
insert into #tbl_Crew_Employees
values
(13,11,'2013-03-30','2013-05-12'),
(12,88,'2013-01-02','2013-04-18'),
(12,66,'2013-01-02','2013-06-30'),
(13,88,'2013-04-19','2013-04-21'),
(11,111,'2013-01-02','2013-04-28')
declare #tbl_TimeEntries table (EmployeeID int, StartDateTime datetime, EndDateTime datetime)
insert into #tbl_TimeEntries
values
(11,'2013-04-18 08:00','2013-04-18 12:00'),
(11,'2013-04-18 12:30','2013-04-18 18:30'),
(111,'2013-04-18 10:00','2013-04-18 12:00'),
(111,'2013-04-18 12:30','2013-04-18 18:30'),
(88,'2013-04-18 11:00','2013-04-18 12:00'),
(88,'2013-04-18 12:30','2013-04-18 19:30'),
(66,'2013-04-18 10:00','2013-04-18 12:00'),
(66,'2013-04-18 12:30','2013-04-18 18:30'),
(11,'2013-04-20 08:00','2013-04-20 12:00'),
(11,'2013-04-20 12:30','2013-04-20 18:00'),
(111,'2013-04-20 10:00','2013-04-20 12:00'),
(111,'2013-04-20 12:30','2013-04-20 18:30'),
(88,'2013-04-20 11:00','2013-04-20 12:00'),
(88,'2013-04-20 12:30','2013-04-20 19:30'),
(66,'2013-04-20 10:00','2013-04-20 12:00'),
(66,'2013-04-20 12:30','2013-04-20 17:00')
SELECT
t.EmployeeID,
c.CrewID,
SUM(DATEDIFF(SECOND, t.StartDateTime, t.EndDateTime) / 60.0
/ 60.0) ,
CAST(t.StartDateTime AS date)
FROM #tbl_TimeEntries t
INNER JOIN
#tbl_Crew_Employees c on
c.EmployeeID = t.EmployeeID
and c.StartDate <= cast(t.StartDateTime as date)
and c.EndDate >= cast(t.EndDateTime as date)
GROUP BY t.EmployeeID, CAST(t.StartDateTime AS date), c.CrewID
ORDER BY CAST(t.StartDateTime AS date)

Related

Date and Time field query

If Date and Time field is having date entry like '2017-12-04 21:30:00.000' and Duration is '1800' and '2017-12-04 21:30:22.000' has '22' then our query should show record as '2017-12-04 21:30:00.000' as '1800' but 22 seconds should come at '2017-12-04 21:30:00.000' but my query is showing at 2017-12-04 21:00:00.000 with Duration as '1822' (sum of 1800+22). I have this question is this link in different manner but didn't get a proper answer hence asking this question here as I'm not able to modify in proper way.
Query:
SELECT Interval=(CASE WHEN datepart(MINUTE,[DateTime]) = 0 and datepart(SECOND,DateTime)=0 THEN
CAST(CONVERT(VARCHAR(30),DATEADD(HOUR,-1,[DateTime]),101) + ' '+ cast(format(DATEPART(HOUR,DATEADD(HOUR,-1,[DateTime])),'0#') as varchar)+':30:00' as DateTime)
ELSE (CAST(CONVERT(VARCHAR(30),[DateTime],101) +' ' + (case when datepart(MINUTE,[DateTime])<=30 and
datepart(SECOND,[DateTime])<59
then cast(format(DATEPART(HOUR,[DateTime]),'0#') as varchar)+':00:00'
else cast(format(DATEPART(HOUR,[DateTime]),'0#') as varchar)+':30:00' end) as DateTime)) END),
ID,Code,Duration=SUM(Duration) FROM Table
WHERE [DateTime] >= '2017-12-04 00:00:00' and [DateTime] <= '2017-12-04 23:59:59'
GROUP BY (CASE WHEN datepart(MINUTE,[DateTime]) = 0 and datepart(SECOND,DateTime)=0 THEN
CAST(CONVERT(VARCHAR(30),DATEADD(HOUR,-1,[DateTime]),101) + ' '+ cast(format(DATEPART(HOUR,DATEADD(HOUR,-1,[DateTime])),'0#') as varchar)+':30:00' as DateTime)
ELSE (CAST(CONVERT(VARCHAR(30),[DateTime],101) +' ' + (case when datepart(MINUTE,[DateTime])<=30 and
datepart(SECOND,[DateTime])<59 then cast(format(DATEPART(HOUR,[DateTime]),'0#') as varchar)+':00:00'
else cast(format(DATEPART(HOUR,[DateTime]),'0#') as varchar)+':30:00' end) as DateTime)) END),
ID,Code
Order by Interval
Actual table data.
DateTime ID Code Duration
2017-12-12 00:30:00 1 12 1800
2017-12-12 00:30:37 1 12 37
2017-12-12 01:00:00 1 12 1793
2017-12-12 01:30:00 1 12 1800
2017-12-12 01:30:59 1 12 59
If I run the query then expected result is,
DateTime ID Code Duration
2017-12-12 00:00:00 1 12 1837
2017-12-12 00:30:00 1 12 1800
2017-12-12 01:00:00 1 12 1800
2017-12-12 01:30:00 1 12 59
DateTime ID Code Duration
2017-12-12 00:00:00 1 12 1800
2017-12-12 00:30:00 1 12 1800
2017-12-12 01:00:00 1 12 1800
2017-12-12 01:30:00 1 12 59
You can use date functions to round [DateTime] into 30 minute intervals, but the result does not match your expected result, which appears to be wrong
DateTime ID Code Duration
2017-12-12 00:30:00 1 12 1800 1800 + 337 = 1837 2017-12-12 00:30
2017-12-12 00:30:37 1 12 37
2017-12-12 01:00:00 1 12 1793 1793 2017-12-12 01:00
2017-12-12 01:30:00 1 12 1800 1800 + 59 = 1859 2017-12-12 01:30
2017-12-12 01:30:59 1 12 59
SQL Fiddle
MS SQL Server 2014 Schema Setup:
CREATE TABLE Table1
([DateTime] datetime, [ID] int, [Code] int, [Duration] int)
;
INSERT INTO Table1
([DateTime], [ID], [Code], [Duration])
VALUES
('2017-12-12 00:30:00', 1, 12, 1800),
('2017-12-12 00:30:37', 1, 12, 37),
('2017-12-12 01:00:00', 1, 12, 1793),
('2017-12-12 01:30:00', 1, 12, 1800),
('2017-12-12 01:30:59', 1, 12, 59)
;
Query 1:
select
dateadd(minute, (datediff(minute, [DateTime], 0) / 30) * 30, 0)
, sum(duration)
from table1
group by
dateadd(minute, (datediff(minute, [DateTime], 0) / 30) * 30, 0)
Results:
| | |
|----------------------|------|
| 1782-01-19T22:30:00Z | 1859 |
| 1782-01-19T23:00:00Z | 1793 |
| 1782-01-19T23:30:00Z | 1837 |

Insert a row for every hour in a date range

I have a table with a StartDate column and an EndDate column. I need to insert into a new table a row for each hour in the date range of the above tables column.
The table I have looks like this
StartDate EndDate
2017-10-25 19:00:00.000 2017-11-30 23:59:59.997
2017-10-26 13:00:00.000 2017-12-1 23:59:59.997
new table I need should look like this
Date Hour
2017-10-25 19
2017-10-25 20
2017-10-25 21
2017-10-25 22
2017-10-25 23
2017-10-26 0
2017-10-26 1
2017-10-26 2
:::::::::: :
:::::::::: :
2017-11-30 22
2017-11-30 23
I am so lost, please help!
Can be done with an ad-hoc tally table in concert with a CROSS APPLY.
Example
Select Date = cast(D as date)
,Hour = datepart(HOUR,D)
From YourTable A
Cross Apply (
Select Top (DateDiff(HOUR,A.StartDate,A.EndDate)+1) D=DateAdd(HOUR,-1+Row_Number() Over (Order By (Select Null)),A.StartDate)
From master..spt_values n1,master..spt_values n2
) B
Returns
Date Hour
2017-10-25 19
2017-10-25 20
2017-10-25 21
2017-10-25 22
2017-10-25 23
2017-10-26 0
2017-10-26 1
2017-10-26 2
2017-10-26 3
...

I want to transform part of columns to rows

I have table A
mon start end tue start end
sub009 13:00 14:00 sub004 15:00 15:30
sub004 14:00 15:00 sub005 15:30 16:00
sub005 15:00 16:00 sub009 16:00 16:30
and I am trying to get this
13:00 14:00 15:00 15:30 16:00 16:30
mon sub009 sub004 sub005
tue sub004 sub005 sub009
please I need help
Assuming you have table like this
table - monday_schedule
___________________________
Subject |startTime |endTime
___________________________
sub009 13:00 14:00
sub004 14:00 15:00
sub005 15:00 16:00
And you are plotting the subject names in the end time column, and all times are in interval of 30 min.
Then query like below will help:
select d,[14:00],[14:30],[15:00],[16:00],[16:30]
from
(select d,Subject, dayss
from
(select 'MON' as d,Subject, startTime, endTime from monday_schedule
UNION
select 'Tue' as d,Subject, startTime, endTime from tuesday_schedule
) s
UNPIVOT
( dayss for hourss in ([endTime]) )up)s
PIVOT
(
Max(Subject) for
dayss in ([14:00],[14:30],[15:00],[16:00],[16:30])
)p
Sample fiddle link : http://sqlfiddle.com/#!6/6ec0a/3

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