Find Gap in Dates SQL - sql

I'm using Microsoft SQL Server and have 2 tables, AbsenceHistory and FITNoteHistory.
AbsenceHistory:
[Employee Number], [Absence Number], [Start Date], [End Date]
FITNoteHistory:
[Absence Number], [FIT Note Number], [Start Date], [End Date]
I need to identify where there is a gap in the FIT Note History, that doesn't cover the entire Absence Period between DateAdd(d,7,AbsenceHistory.[Start Date]) and AbsenceHistory.[End Date], where AbsenceHistory.[End Date] is not null and DATEDIFF(d,AbsenceHistory.[Start Date],AbsenceHistory.[End Date]) >= 7.
The output needs to give me the actual date gaps for each absence.
E.g. Absence Number, Date of Gap
Can anyone help?
Example Data:
AbsenceHistory:
[Employee Number], [Absence Number], [Start Date], [End Date]
18615, 70, '01-Jan-2018', '31-Jan-2018'
FITNoteHistory:
[Absence Number], [FIT Note Number], [Start Date], [End Date]
70, 1, '08-Jan-2018', '15-Jan-2018'
70, 15, '18-Jan-2018', '24-Jan-2018'
70, 31, '26-Jan-2018', '01-Feb-2018'
My expected output would be:
[Employee Number], [Absence Number], [Gap Date]
18615, 70, '16-Jan-2018'
18615, 70, '17-Jan-2018'
18615, 70, '25-Jan-2018'

This should get you started
declare #t table ([Absence Number] int, [FIT Note Number] int, [Start Date] date, [End Date] date)
insert into #t values
(70, 1, '08-Jan-2018', '15-Jan-2018')
, (70, 15, '18-Jan-2018', '24-Jan-2018')
, (70, 31, '26-Jan-2018', '01-Feb-2018');
select t.[Absence Number], t.[FIT Note Number], t.[Start Date], t.[End Date]
from #t t
order by t.[Start Date], t.[End Date], t.[FIT Note Number];
declare #minDate date = (select min([End Date]) from #t);
declare #maxDate date = (select max([Start Date]) from #t);
with cteDate as
(
select #minDate as dDate
union all
select cast(dateadd(dd, 1, dDate) as date)
from cteDate
where dDate < #maxDate
)
, cteNext as
( select t.[Absence Number], t.[FIT Note Number], t.[Start Date], t.[End Date]
, lead(t.[Start Date], 1) OVER (ORDER BY t.[Start Date]) AS nextStart
from #t t
)
select n.[Absence Number], n.[FIT Note Number], n.[Start Date], n.[End Date]
, d.dDate
from cteNext n
join cteDate d
on d.dDate > n.[End Date]
and d.dDate < n.nextStart
order by d.dDate;

Related

SQL Server / SSMS - Error Converting nvarchar to float

I have checked Temp_Calc_1 against Temp_Calc_2 and they both have the same column datatypes (float, nvarchar(255)) and are in the same order when reading down the table. When I try to run this on the empty Temp_Calc_2, I get an error:
Error converting nvarchar to float
on the line INSERT INTO dbo.Temp_Calc_2
USE MfgMetrics
INSERT INTO dbo.Temp_Calc_2
SELECT
zps.[Plant], [Work Center],
[Scheduled start Date], [SCHEDULE START TIME],
[SCHEDULED FINISHED DATE], [SCHEDULED FINISHED TIME],
[MATERIAL NUMBER], [MATERIAL DESCRIPTON],
[ORDER NUMBER], [ORDER TYPE],
[PLANNED QUANTITY], [PLANNED QTY - PROD UN],
[DELIVERED QTY], [DELIVERED QTY - PROD UN],
[RemainingQty(BUn)], [REMAINING QTY - Prod Un],
[COMMITED QTY], [COMMITED QTY - PROD UN], [UOM],
[STORAGE LOCATION], [COMMENTS],
[RATE QUANTITY], [RATE QUANTITY - PROD UN], [RATE HOUR],
[OPERATING EFFIECIENCY], [UNIT],
[STD UNITS / HR], [STD UNITS / HR - PROD UN], [UOM2],
[ORDER STATUS], [ACTUAL START DATE], [ACTUAL START TIME],
[MRP CONTROLLER], [CREATED ON], [TIME CREATED],
[CHANGED ON], [TIME CHANGE],
[ORDER TEXT LINES], [ORDER TEXT 2nd LINE], [FileDate],
scf.[OQ_RxnTime_(mins)], scf.[RunDurThreshold_(hrs)],
CASE
WHEN (zps.[MATERIAL NUMBER] LIKE '%.%')
THEN zps.[MATERIAL NUMBER]
WHEN ISNUMERIC(zps.[MATERIAL NUMBER]) = 1
THEN CAST(CAST(zps.[MATERIAL NUMBER] AS INT) AS NVARCHAR(255))
ELSE zps.[MATERIAL NUMBER]
END As [Material],
(CAST(CAST(zps.[ORDER NUMBER] AS INT) AS NVARCHAR(255)) + '_' + CAST(CAST(zps.[PLANNED QUANTITY] AS INT) AS NVARCHAR(255))) AS Order_Quantity,
scf.[OQ_RxnTime_(mins)] * zps.[STD UNITS / HR] / 60 AS OQWindow
FROM
Temp_Calc_1 zps
INNER JOIN
SAWorkCenters swc ON zps.Plant = swc.Plant
AND zps.[Work Center] = swc.WCGroup
INNER JOIN
SchedAttCalcFactors scf ON zps.Plant = scf.[Plant Code]
ORDER BY
zps.Plant, zps.[Work Center], zps.[ORDER NUMBER], zps.FileDate
GO

how to get only overlapping records based on start and end date?

I have a table and query as follow:
I am trying to get overlapping records between [Assignment Start Date] and [Assignment End Date] for same Employee Id.
In short I need data for those Employee Id which are allocated for same time period or overlapping time period from below example.
e.g.
[Employee Id] [Assignment Start Date] [Assignment End Date] [Allocation Percentage]
100 2016-03-01 2017-02-28 100
102 2016-06-01 2016-12-31 100
102 2016-07-01 2016-10-30 100
102 2016-11-01 2017-01-31 100
103 2017-02-01 2017-05-30 100
102 2017-04-01 2017-06-30 100
102 2017-11-01 2017-01-31 100
104 2017-02-01 2017-05-01 100
CREATE TABLE #Result
(
PK INT IDENTITY(1,1),
[BU] VARCHAR(20),
[Division] VARCHAR(20),
[Product Name] VARCHAR(30),
[Employee ID] NVARCHAR(20),
[Resource Name] VARCHAR(50),
[Resource_ID] INT,
[Assignment Start Date] DATE,
[Assignment End Date] DATE,
[Allocation Percentage] INT,
[Location] VARCHAR(100),
[Development Manager] VARCHAR(50),
[Allocation] VARCHAR(20)
);
SELECT DISTINCT r1.PK, r1.Resource_ID,r1.[Employee ID], r1.[Assignment Start Date] AS 'Start 1' ,r1.[Assignment End Date] AS 'End 1' , r2.[Assignment Start Date] , r2.[Assignment End Date]
INTO #temp1
FROM #Result r1
INNER JOIN #Result r2
ON r1.[Employee ID] = r2.[Employee ID]
AND (r1.PK <> r2.PK)
AND ((r1.[Assignment Start Date] <= r2.[Assignment Start Date]) AND (r1.[Assignment End Date] >= r2.[Assignment Start Date]))
OR ((r1.[Assignment Start Date] > r2.[Assignment Start Date] AND r1.[Assignment Start Date] <= r2.[Assignment End Date]) AND (r1.[Assignment End Date] <= r2.[Assignment End Date]))
OR ((r1.[Assignment Start Date] > r2.[Assignment Start Date] AND r1.[Assignment Start Date] <= r2.[Assignment End Date]) AND (r1.[Assignment End Date] > r2.[Assignment End Date]))
OR (r1.[Assignment Start Date] = r2.[Assignment End Date])
I have tried using above query but it gives all records related to overlapping employee even if that entry for that employee is not overlapping.
In above example there is a Employee Id 102 which has 2 overlapping entries and 3rd entry which is not overlapping I want to remove it from this result. please help.
CTE, row_number and a self join
with CTE as
(
select PK, Resource_ID, [Employee ID] as Emp_ID, [Assignment Start Date] as s_Date, [Assignment End Date] as e_date,
row_number() over(partition by [Employee ID] order by [Assignment Start Date] ) as rn
from #Result
)
select t1.*, t2.*
from CTE t1
inner join CTE t2
on t1.Resource_ID = t2.Resource_ID
and t1.Emp_ID = t2.Emp_ID
and t2.rn = t1.rn +1
where t2.s_date <= t1.e_date
or t1.e_date is null -- allows for null end date
Your SQL query should look like that below:
SELECT DISTINCT r1.PK, r1.Resource_ID,r1.[Employee ID], r1.[Assignment Start Date] AS 'Start 1' ,r1.[Assignment End Date] AS 'End 1' , r2.[Assignment Start Date] , r2.[Assignment End Date]
INTO #temp1
FROM #Result r1
JOIN #Result r2 on r1.[Employee ID] = r2.[Employee ID]
WHERE (
(r2.[Assignment Start Date] BETWEEN r1.[Assignment Start Date] and r1.[Assignment End Date])
or
(r2.[Assignment End Date] between p1.[Assignment Start Date] and p1.[Assignment End Date])
)
AND r1.PK <> r2.PK

Data Table with Current Week and Those Dates One Year Ago

I'm trying to create one sql table with the current week's data (always changing) as well as those dates data from the previous year. I have multiple tables that I have to join but am not sure how to create it all into one table. Here is what I have so far:
------- CURRENT YEAR -------
DECLARE
#CURRENTDATE DATE,
#BEGINDATE DATE
SET #CURRENTDATE = CONVERT(DATE,GETDATE()) ---// TODAY'S DATE //---
SET #BEGINDATE = DATEADD(DAY, -7, GETDATE()) ---// A WEEK BEFORE TODAY'S DATE //---
SELECT SALES.*, RECRUITS.Recruits
FROM
(
SELECT
CONVERT(VARCHAR(10), A.[ORDER DATE], 101) AS 'DAY'
, 'Sales Revenue Current Year' = FORMAT(SUM(A.[GRAND TOTAL]) ,'C', 'EN-US')
, 'Comm. Sales Volume Current Year' = FORMAT(sum(a. [QUALIFYING VOLUME]), 'C', 'EN-US')
FROM TABLE1 a
WHERE CONVERT(VARCHAR(10), A.[ORDER DATE], 101) >= #BEGINDATE AND CONVERT(VARCHAR(10), A.[ORDER DATE], 101) < #CURRENTDATE
GROUP BY CONVERT(VARCHAR(10), A.[ORDER DATE], 101)
) SALES,
(
SELECT
CONVERT(VARCHAR(10),a.[start date],101) AS 'DAY'
,count(b.[id number]) as Recruits
from TABLE2 a
left join
TABLE3 b
on a.enroller = b. [id number]
WHERE CONVERT(VARCHAR(10), A.[START DATE], 101) >= #BEGINDATE AND CONVERT(VARCHAR(10), A.[START DATE], 101) < #CURRENTDATE
group by a.[start date]
) RECRUITS
WHERE SALES.DAY = RECRUITS.DAY
I have the same script for the previous year. It is the same except I set the dates to -366 and -373 days. Any help would be great!
You can use multiple dates with an "OR", like below, but a better solution would be to use a date dimensional table, a list of every daily date with things like "WeekOfYear", "WeekOfMonth", "QuarterOfYear", "IsHoliday", etc. Then you can join your date against that table and query "where t1.WeekOfYear = t2.WeekOfYear".
DECLARE
#EndDate DATE = GETDATE() ---// TODAY'S DATE //---
, #StartDate DATE = DATEADD(DAY, -7, GETDATE()) ---// A WEEK BEFORE TODAY'S DATE //---
, #LYStartDate DATE = DATEADD(YEAR, -1, GETDATE()) ---// A YEAR BEFORE TODAY'S DATE //---
, #LYEndDate DATE = DATEADD(DAY, -7, DATEADD(YEAR, -1, GETDATE())) ---// A YEAR AND A WEEK BEFORE TODAY'S DATE //---
SELECT SALES.*, RECRUITS.Recruits
FROM
(
SELECT
'DAY' = CONVERT(VARCHAR(10), A.[ORDER DATE], 101)
, 'Sales Revenue Current Year' = FORMAT(SUM(A.[GRAND TOTAL]) ,'C', 'EN-US')
, 'Comm. Sales Volume Current Year' = FORMAT(sum(a. [QUALIFYING VOLUME]), 'C', 'EN-US')
FROM TABLE1 a
WHERE (
(CAST(A.[ORDER DATE] AS DATE) >= #StartDate AND CAST(A.[ORDER DATE] AS DATE) <= #EndDate)
OR
(CAST(A.[ORDER DATE] AS DATE) >= #LYStartDate AND CAST(A.[ORDER DATE] AS DATE) <= #lyEndDate)
)
GROUP BY CAST(A.[ORDER DATE] AS DATE)
) SALES,
(
SELECT
'DAY' = CAST(a.[start date] AS DATE)
, Recruits = COUNT(b.[id number])
FROM TABLE2 a
LEFT JOIN TABLE3 b
ON a.enroller = b. [id number]
WHERE (
(CAST(A.[START DATE] AS DATE) >= #StartDate AND CAST(A.[ORDER DATE] AS DATE) <= #EndDate)
OR
(CAST(A.[START DATE] AS DATE) >= #lyStartDate AND CAST(A.[ORDER DATE] AS DATE) <= #LYEndDate)
GROUP BY CAST(a.[start date] AS DATE)
) RECRUITS
WHERE SALES.DAY = RECRUITS.DAY

for every row get all dates between columns and insert into column

I have table variable that I fill with all dates between a particular range (and the dw,wk,mm,yy,dd values)
I then join this to my inspection records by the start date.
SELECT CalDate
, DayN
, WeekN
, YearN
, DayOfMonthN
, [Start Date]
, [End Date]
, [Inspection Number]
FROM #Calendar AS dateInfo
LEFT JOIN [Inspection Records] AS IR
ON IR.[Start Date] = dateInfo.CalendarDate
This works fine, what I am now needing to do (and i have to do it this way to pass to a 3rd party application...) is get all the dates between the [Start Date] and [End Date] and add them into a column as a comma separated list.
I've come across this answer t-sql get all dates between 2 dates
that seems to get the dates perfectly for what I need.
I'm stuck on how to structure my script to use that script to get all the dates between my [Start Date] and [End Date] and add them into a column.
what is the best way to calculated all dates between my two columns
how to insert the outcome into a single column as comma separated list
NOTE: I can not add anything to the database.
Example: (Trying to get the dates column)
<table>
<tr>
<td>CalDate</td>
<td>DayN</td>
<td>WeekN</td>
<td>YearN</td>
<td>DayOfMonthN</td>
<td>Start Date</td>
<td>End Date</td>
<td>Inspection Number</td>
<td>Dates</td>
</tr>
<tr>
<td>07-08-2014</td>
<td>5</td>
<td>32</td>
<td>2014</td>
<td>7</td>
<td>07-08-2014</td>
<td>11-08-2014</td>
<td>A0001</td>
<td>07-08-2014,08-08-2014,09-08-2014,10-08-2014,11-08-2014</td>
</tr>
</table>
SELECT CalDate
, DayN
, WeekN
, YearN
, DayOfMonthN
, [Start Date]
, [End Date]
, [Inspection Number]
, [Dates] = STUFF((
SELECT ',' + CONVERT(VARCHAR(10), C.CalDate,105)
FROM #Calendar AS C
WHERE C.CalDate BETWEEN IR.[Start Date] AND IR.[End Date]
FOR XML PATH('')
), 1, 1, '')
FROM #Calendar AS dateInfo
LEFT JOIN [Inspection Records] AS IR
ON IR.[Start Date] = dateInfo.CalendarDate
This will put all your dates into a variable named #csv.
I'm sure you'll be able to modify to suit your needs.......
DECLARE #csv nVarchar(max)
SELECT #csv = COALESCE(#csv + ', ', '') + CONVERT(Nvarchar(20), yourDateColumn)
FROM yourDateTable

Convert date and find date

I'm having some trouble with syntax.
First, I'd like to convert a date from this format:
2014-12-18 21:49:54.047
To this format:
20141218
I can do this just fine using this select statement:
SELECT F253 = CONVERT (VARCHAR (20), F253, 112)
FROM SAL_HDR
My problem is with the syntax. How do I put that select statement inside of a select statement with a bunch of other lines? I can't seem to make it work right. I have commented out the line in question. How do I write that line into the larger select statement?
SELECT
SAL_HDR.F253 AS [Transaction Date],
/*F253 = CONVERT (VARCHAR (20), F253, 112)*/
SAL_HDR.F1036 AS [Transaction Time],
SAL_HDR.F1032 AS [Transaction #],
FROM SAL_HDR
Just add it in as an expression:
SELECT CONVERT(VARCHAR(20), SAL_HDR.F253, 112) AS [Transaction Date],
SAL_HDR.F1036 AS [Transaction Time],
SAL_HDR.F1032 AS [Transaction #]
FROM SAL_HDR;
Alternatively, you can use the syntax:
SELECT [Transaction Date] = CONVERT(VARCHAR(20), SAL_HDR.F253, 112),
[Transaction Time] = SAL_HDR.F1036,
[Transaction #] = SAL_HDR.F1032
FROM SAL_HDR;
I personally prefer the first version, because I find that the second is too close to variable assignment.