SQL missing dates null value how to fill - sql

Hi how do i fill up the null value with e.g id, name
from the left join table
SQL:
DECLARE #startDate DATETIME, #endDate DATETIME
SELECT #startDate = '2015-11-18', #endDate = '2015-11-20' --yyyy-mm-dd
;WITH Calender AS (
SELECT #startDate AS WorkDate
UNION ALL
SELECT WorkDate + 1 FROM Calender
WHERE WorkDate + 1 <= #endDate
), -- generate date from to --
cte AS (
SELECT COUNT(*) OVER() AS 'total' ,ROW_NUMBER()OVER (ORDER BY c.dt DESC) as row
, c.*
FROM Calender d
LEFT JOIN clockL c ON c.dt = d.WorkDate AND c.id = 17
) -- select user log and add missing dates --
SELECT *
FROM cte
--WHERE row BETWEEN 0 AND 15
--option (maxrecursion 0)
Result:
total row badgenumber id name title deptname ld dt min mout ain aout nin nout
----------- -------------------- ----------- ----------- ---------------------------------------- -------------------- ------------------------------ ---------------- ------------ ------------ ------------ ------------ ------------ ------------ ------------
3 1 1 17 James HQ 2015-11-19 08:31 2015-11-19 08:31 NOC NOC NOC NOC NOC
3 2 1 17 James HQ 2015-11-18 20:37 2015-11-18 08:30 13:14 16:28 20:37 NOC NOC
3 3 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
^ ^ ^ ^ ^
should be 1 shoud be 17 James HQ 2015-11-20
thank you for looking :), i looked and tried but failed.

Related

How to display multiple rows based row difference data In SQL?

I have a table as follows:
EmpID FromYM ToYM EmpYl EmpX1
----- ------ ----- ------ ----------
1001 202101 202101 20210103 20210103
1001 202102 202103 20210103 20210103
I want to split this data based on above data.
If FromYm(Means yearmonth) and ToYM(Means yearmonth) difference is two then result as two rows:
Example result :
EmpID FromYM ToYM EmpYl DiffNoCount
------ ------ ---- ----- ------
1001 202101 202101 20210103 1
1001 202102 202103 20210103 1
1001 202102 202103 20210103 2
Tried Code
IF OBJECT_ID(N'tempdb..#rawdata1') IS NOT NULL
BEGIN
DROP TABLE #rawdata1
END
IF OBJECT_ID(N'tempdb..#rawdata2') IS NOT NULL
BEGIN
DROP TABLE #rawdata2
END
go
declare #Max as int
declare #Kount as int
Set #Kount = 1
SELECT row_number() Over (order by EmpID) as row,EmpID
,FromYM
,ToYM
, EmpYl
,EmpX1
into #rawdata1
FROM [dbo].[ASAAValue1]
order by EmpID
set #Max = (Select Max(FromYM) from #rawdata1)
Create Table #Rawdata2
(
[Row] int,
Rolling int,
RollingAvg decimal(15,2),
RollingFinal int
)
while (#kount < #max)
Begin
Insert into #rawdata2
select #Kount as Row , FromYM as Rolling
, ToYM as RollingAvg,
Case When Convert(int,Convert(nvarchar(6),EmpYl))>=FromYM
Then <br>
FromYM <br>
Else<br>
FromYM+1 <br>
End <br>
from #rawdata1<br>
where row between #Kount - 12 and #Kount <br>
set #Kount = #Kount + 1
end
select rd1.row,
rd1.EmpID,Rd1.FromYM,Rd1.ToYM,Rd1.EmpYl, rd2.RollingFinal as Final from #rawdata2 rd2
inner join #rawdata1 rd1
on rd1.row = rd2.row
You can do it using recursive cte:
with data as (
select '202101' as f, '202101' as t union all
select '202102' as f, '202103' as t
),
rcte as (
select *, 1 as n from data
union all
select f, t, n + 1
from rcte
where n <= datediff(month, convert(date, f + '01', 112), convert(date, t + '01', 112))
)
select * from rcte
You can test on this db<>fiddle

Multiple rows in to single row in SQL Server if each column has only one value per employee

How to do this please help.
I have the following data. This is a data sample for week. I want single row per EmployeeName / CrewID (unless there are 2 values for a Employee in a single date).
If ORIGINAL DATA is like this :
2018-08-05 2018-08-06 2018-08-07 2018-08-08 2018-08-09 2018-08-10 2018-08-11 CrewID EmployeeName
------------ ------------ ------------ ------------ ------------ ------------ ------------ -------- ----------------
NULL 174 173 172 171 NULL NULL 9 Kanhaiya
NULL NULL NULL NULL NULL 178 NULL 9 Kanhaiya
NULL 174 173 172 171 NULL NULL 8 Santanu Maulik
NULL NULL NULL NULL NULL 178 NULL 8 Santanu Maulik
The OUTPUT of the above original should be in single row per person as below.
2018-08-05 2018-08-06 2018-08-07 2018-08-08 2018-08-09 2018-08-10 2018-08-11 CrewID EmployeeName
------------ ------------ ------------ ------------ ------------ ------------ ------------ -------- ----------------
NULL 174 173 172 171 178 NULL 9 Kanhaiya
NULL 174 173 172 171 178 NULL 8 Santanu Maulik
but still the data may be spitted in multiple rows per employee for certain condition like if the employee has multiple values for a single date eg. '2018-08-10'
If ORIGINAL DATA is like this :
2018-08-05 2018-08-06 2018-08-07 2018-08-08 2018-08-09 2018-08-10 2018-08-11 CrewID EmployeeName
------------ ------------ ------------ ------------ ------------ ------------ ------------ -------- --------------
NULL 174 173 172 171 NULL NULL 9 Kanhaiya
NULL NULL NULL NULL 163 178 NULL 9 Kanhaiya
The OUTPUT of the above original data should be like below.
2018-08-05 2018-08-06 2018-08-07 2018-08-08 2018-08-09 2018-08-10 2018-08-11 CrewID EmployeeName
------------ ------------ ------------ ------------ ------------ ------------ ------------ -------- --------------
NULL 174 173 172 171 178 NULL 9 Kanhaiya
NULL NULL NULL NULL 163 NULL NULL 9 Kanhaiya
I have managed to get the data with a stored procedure.
This is the main logic section of the stored procedure:
ALTER PROCEDURE [dbo].[GetDataForCustomWeekViewReport]
#Week AS INT,
#typeOfData AS VARCHAR(10)
AS
BEGIN
DECLARE #weekAdjustAdd INT
SET NOCOUNT ON;
SET DATEFIRST 7;
SET #weekAdjustAdd = (#Week - 1) * 7
DECLARE #SQLQuery AS NVARCHAR(MAX)
DECLARE #PivotColumns AS NVARCHAR(MAX)
-----------------------------
-- Get unique values of pivot column
SELECT
#PivotColumns= COALESCE(#PivotColumns + ',','') + QUOTENAME(WORKDAYS)
FROM
(SELECT DISTINCT WORKDAYS
FROM
(SELECT
DATEADD(DAY, #weekAdjustAdd, CAST(DATEADD(WEEK, DATEDIFF(DAY, -1, GETDATE()) / 7, -1) AS date)) AS WORKDAYS
UNION
SELECT
DATEADD(DAY, #weekAdjustAdd, CAST(DATEADD(WEEK, DATEDIFF(DAY, -1, GETDATE()) / 7, 0) AS date)) AS WORKDAYS
UNION
SELECT
DATEADD(DAY, #weekAdjustAdd, CAST(DATEADD(WEEK, DATEDIFF(DAY, -1, GETDATE()) / 7, 1) AS date)) AS WORKDAYS
UNION
SELECT
DATEADD(DAY, #weekAdjustAdd, CAST(DATEADD(WEEK, DATEDIFF(DAY, -1, GETDATE()) / 7, 2) AS date)) AS WORKDAYS
UNION
SELECT
DATEADD(DAY, #weekAdjustAdd, CAST(DATEADD(WEEK, DATEDIFF(DAY, -1, GETDATE()) / 7, 3) AS date)) AS WORKDAYS
UNION
SELECT
DATEADD(DAY, #weekAdjustAdd, CAST(DATEADD(WEEK, DATEDIFF(DAY, -1, GETDATE()) / 7, 4) AS date)) AS WORKDAYS
UNION
SELECT
DATEADD(DAY, #weekAdjustAdd, CAST(DATEADD(WEEK, DATEDIFF(DAY, -1, GETDATE()) / 7, 5) AS date)) AS WORKDAYS
) i) AS PivotExample
IF (#typeOfData = 'f')
BEGIN
--Get unique values of pivot column
--Create the dynamic query with all the values for
--pivot column at runtime
--',JOBID, JobInfo,CrewID, EmployeeName,Color
-- ,JI.INumber + '' - '' + JI.ITitle AS JobInfo, M.Color,
SET #SQLQuery =
N'
DECLARE #Week AS int
DECLARE #weekAdjustAdd int
SET #Week=1
SET DATEFIRST 7;
SET #weekAdjustAdd = (#Week - 1) * 7
SELECT ' + #PivotColumns + ', CrewID, EmployeeName
FROM (
SELECT J.ID AS JOBID, C.ID AS CrewID ,c.CrewName AS EmployeeName , JI.ID AS JOBINSTANCE_ID,JI.WORKDAYS
FROM [dbo].[Job] J
LEFT JOIN [dbo].[Job_Instances] JI ON J.ID=JI.JOBID
LEFT JOIN [dbo].[Instance_Employee_Relation] IER ON JI.ID=IER.JobInstanceID
LEFT JOIN [dbo].[Crew] C ON C.Id = IER.EMPLOYEEID
INNER JOIN [dbo].[Manager] M ON M.Id = JI.ManagerID
INNER JOIN dbo.JobType JT ON JT.ID = JI.JobTypeID
WHERE ( C.EmployeeTypeID=1 OR C.EmployeeTypeID IS NULL) AND JI.TYPE = ''F'' AND JI.WORKDAYS BETWEEN DATEADD(DAY,'+CONVERT(VARCHAR(20) ,#weekAdjustAdd)+', CAST(DATEADD(WEEK, DATEDIFF(DAY, -1, GETDATE()) / 7, -1) AS date)) AND DATEADD(DAY,'+ CONVERT(VARCHAR(20) ,#weekAdjustAdd)+', CAST(DATEADD(WEEK, DATEDIFF(DAY, -1, GETDATE()) / 7, 5) AS date))
)i
PIVOT( SUM(JobInstance_ID)
FOR [WORKDAYS] IN (' + #PivotColumns + ')) AS P ORDER BY CASE WHEN EmployeeName IS NULL THEN 1 ELSE 0 END, EmployeeName'
--Execute dynamic query
EXEC sp_executesql #SQLQuery
END
Here is the main schema section for the related tables.
UPDATE
#Ven tried to help me out & did a good job but his answer is working if i have only 2 rows per employee but if i have more than 2 rows per employee his solution is not working.
Original Data
2018-08-05 2018-08-06 2018-08-07 2018-08-08 2018-08-09 2018-08-10 2018-08-11 CrewID EmployeeName
------------ ------------ ------------ ------------ ------------ ------------ ------------ -------- ----------------
NULL 174 173 172 171 NULL NULL 9 Kanhaiya
NULL NULL NULL NULL NULL 178 NULL 9 Kanhaiya
NULL NULL NULL NULL 183 182 NULL 8 Santanu Maulik
NULL NULL NULL NULL NULL 178 NULL 8 Santanu Maulik
NULL 174 173 172 171 NULL NULL 8 Santanu Maulik
Output with #Ven's Solution (did not work For CrewID 8 as he has 3 Rows but worked for CrewID 9 as he has 2 Rows.)
CrewID EmployeeName 2018-08-05 2018-08-06 2018-08-07 2018-08-08 2018-08-09 2018-08-10 2018-08-11
-------- ---------------- ------------ ------------ ------------ ------------ ------------ ------------ ------------
8 Santanu Maulik NULL NULL NULL NULL NULL 178 NULL
8 Santanu Maulik NULL NULL NULL NULL 183 182 NULL
8 Santanu Maulik NULL 174 173 172 171 NULL NULL
9 Kanhaiya NULL 174 173 172 171 178 NULL
Work this out in 3 different steps to satisfy requirements. There is no other dirty way of doing this :)
1) Get previous row and next row in table by self join (left join)
2) Case expression to get value from next row where value is null in first row and non-null
in second row
2) case Expression if both rows are equal then null value in second row
DECLARE #table TABLE (
id INT identity(1, 1)
,[2018-08-05] INT
,[2018-08-06] INT
,[2018-08-07] INT
,[2018-08-08] INT
,[2018-08-09] INT
,[2018-08-10] INT
,[2018-08-11] INT
,CrewID INT
,EmployeeName VARCHAR(20)
)
INSERT #table
------------ ------------ ------------ ------------ ------------ ------------ ------------ -------- ----------------
SELECT NULL
,174
,173
,172
,171
,NULL
,NULL
,9
,'Kanhaiya'
UNION ALL
SELECT NULL
,NULL
,NULL
,NULL
,163
,178
,NULL
,9
,'Kanhaiya'
UNION ALL
SELECT NULL
,174
,173
,172
,171
,NULL
,NULL
,8
,'Santanu Maulik'
UNION ALL
SELECT NULL
,NULL
,NULL
,NULL
,NULL
,178
,NULL
,8
,'Santanu Maulik';
Script:
WITH CTE
AS (
SELECT rownum = ROW_NUMBER() OVER (
PARTITION BY p.crewid ORDER BY p.crewID
)
,p.*
FROM #table p
)
,ct2
AS (
SELECT TOP 100 PERCENT cte.CrewID
,cte.employeename
,CASE WHEN cte.[2018-08-05] IS NULL THEN nex.[2018-08-05] ELSE cte.[2018-08-05] END [2018-08-05]
,CASE WHEN cte.[2018-08-06] IS NULL THEN nex.[2018-08-06] ELSE cte.[2018-08-06] END [2018-08-06]
,CASE WHEN cte.[2018-08-07] IS NULL THEN nex.[2018-08-07] ELSE cte.[2018-08-07] END [2018-08-07]
,CASE WHEN cte.[2018-08-08] IS NULL THEN nex.[2018-08-08] ELSE cte.[2018-08-08] END [2018-08-08]
,CASE WHEN cte.[2018-08-09] IS NULL THEN nex.[2018-08-09] ELSE cte.[2018-08-09] END [2018-08-09]
,CASE WHEN cte.[2018-08-10] IS NULL THEN nex.[2018-08-10] ELSE cte.[2018-08-10] END [2018-08-10]
,CASE WHEN cte.[2018-08-11] IS NULL THEN nex.[2018-08-11] ELSE cte.[2018-08-11] END [2018-08-11]
FROM CTE
LEFT JOIN CTE prev ON prev.rownum = CTE.rownum - 1
LEFT JOIN CTE nex ON nex.rownum = CTE.rownum + 1
ORDER BY cte.CrewID
)
,ct3
AS (
SELECT DISTINCT CrewID
,EmployeeName
,CASE WHEN [2018-08-05] = LEAD([2018-08-05]) OVER (
PARTITION BY crewid ORDER BY [2018-08-05]
) THEN NULL ELSE [2018-08-05] END [2018-08-05]
,CASE WHEN [2018-08-06] = LEAD([2018-08-06]) OVER (
PARTITION BY crewid ORDER BY [2018-08-06]
) THEN NULL ELSE [2018-08-06] END [2018-08-06]
,CASE WHEN [2018-08-07] = LEAD([2018-08-07]) OVER (
PARTITION BY crewid ORDER BY [2018-08-07]
) THEN NULL ELSE [2018-08-07] END [2018-08-07]
,CASE WHEN [2018-08-08] = LEAD([2018-08-08]) OVER (
PARTITION BY crewid ORDER BY [2018-08-08]
) THEN NULL ELSE [2018-08-08] END [2018-08-08]
,CASE WHEN [2018-08-09] = LEAD([2018-08-09]) OVER (
PARTITION BY crewid ORDER BY [2018-08-09]
) THEN NULL ELSE [2018-08-09] END [2018-08-09]
,CASE WHEN [2018-08-10] = LEAD([2018-08-10]) OVER (
PARTITION BY crewid ORDER BY [2018-08-10]
) THEN NULL ELSE [2018-08-10] END [2018-08-10]
,CASE WHEN [2018-08-11] = LEAD([2018-08-11]) OVER (
PARTITION BY crewid ORDER BY [2018-08-11]
) THEN NULL ELSE [2018-08-11] END [2018-08-11]
FROM ct2
)
SELECT *
FROM ct3
WHERE isnull([2018-08-05], 0) + isnull([2018-08-06], 0) + isnull([2018-08-07], 0) + isnull([2018-08-08], 0) + isnull([2018-08-09], 0) + isnull([2018-08-10], 0) + isnull([2018-08-11], 0) > 0

Merge two records date if dates are continuous and key values are same

I have two different scenarios. In the first scenario I need something like:
create table test
(
ItemID int,
ItemStartDate datetime,
ItemEndDate datetime,
itemType varchar(100)
)
Table test:
ItemID ItemStartDate ItemEndDate itemType
------ ------------- ----------- --------
item_1 1/1/2011 3/2/2011 value A
item_1 3/3/2011 12/31/2011 value A
item_2 1/3/2011 12/31/2011 value B
It should show only two records:
ItemID ItemStartDate ItemEndDate itemType
------ ------------- ----------- --------
item_1 1/1/2011 12/31/2011 value A
item_2 1/1/2011 12/31/2011 value B
Scenario 2.
Here I would like to split data value to separate year periods if it's across multiple years.
Table test
create table #Scenario_2
(
ItemID int,
priceStartDate datetime,
priceEndDate datetime,
price int
)
item startdate enddate value
---- --------- ---------- -----
11 1/1/2011 5/4/2013 500
12 7/1/2013 11/12/2013 600
It should show like
item startdate enddate value
---- --------- ---------- -----
11 1/1/2011 12/31/2011 500
11 1/1/2012 12/31/2012 500
11 1/1/2013 5/4/2013 500
12 7/1/2013 11/12/2013 600
Please advise how I can achieve this.
Try this. from your question this is what i understood!!
SCENARIO 2
----------
CREATE TABLE #datt
(
itemid int,startd DATE,endat DATE,price int
)
INSERT INTO #datt
VALUES (11,'2011-01-01','2013-05-04',500),
(12,'2013-7-1','2013-11-12',600)
;WITH cte
AS (SELECT itemid,
startd st,
case when year(endat)<> YEAR(startd) then Dateadd(yy, Year(startd) - 1899, -1)
else endat end ed,price
FROM #datt
UNION ALL
SELECT a.itemid,
Dateadd(yy, 1, st),
CASE
WHEN Dateadd(yy, 1, ed) > b.endat THEN b.endat
ELSE Dateadd(yy, 1, ed)
END,a.price
FROM cte a
JOIN #datt b
ON a.itemid = b.itemid
AND a.ed < b.endat)
SELECT *
FROM cte order by itemid,st
For scenario1 you could see this answer.
For scenario2 there also have a similar answer you could reference.
But your question can be simplified like this:
with dates as
(
select number,cast(ltrim(number*10000+1231) as date) as dt
from master..spt_values
inner join
(select min(year(startdate)) as s_year
,max(year(enddate)) as e_year
from Scenario_2) as y
on number between y.s_year and y.e_year AND TYPE='P'
)
select
s.item
,case when year(dt) = year(startdate)
then startdate
else dateadd(year,-1,dateadd(day,1,dt)) end --or cast(ltrim(year(dt)*10000+101) as date)
,case when year(dt) = year(enddate)
then enddate
else dt end
,s.value
from
Scenario_2 s
inner join
dates d
on
d.number between year(s.startdate) and year(s.enddate)
SQL FIDDLE DEMO

Weird SQL Conditions date , STUCK

I and creating view in SQL Server
Below is my Results , based on this I have to actually achieved the results shown below in the second table
PersonID MonthYear DateTimevalue
---------- ---------- --------------
1 201101 NULL
1 201102 NULL
1 201103 2011-03-10 09:35:57.387
1 201104 2011-04-26 13:25:00.050
1 201105 NULL
1 201106 NULL
1 201107 2011-07-30 16:49:26.050
1 201108 NULL
1 201109 2011-09-21 13:33:42.273
1 201110 2011-10-20 08:55:59.873
1 201111 NULL
1 201112 NULL
So , the case when the DateTimeValue is NULL , we need to take the value from previous month
As shown in the below table
PersonID MonthYear DateTimevalue
---------- ---------- --------------
1 201101 NULL
1 201102 NULL
1 201103 2011-03-10 09:35:57.387
1 201104 2011-04-26 13:25:00.050
1 201105 2011-04-26 13:25:00.050
1 201106 2011-04-26 13:25:00.050
1 201107 2011-07-30 16:49:26.050
1 201108 2011-07-30 16:49:26.050
1 201109 2011-09-21 13:33:42.273
1 201110 2011-10-20 08:55:59.873
1 201111 2011-10-20 08:55:59.873
1 201112 2011-10-20 08:55:59.873
Any help would be great !!!!
Thanks !!!!
Thanks !!!
Try the following:
SELECT A.PersonID,
A.MonthYear,
ISNULL(A.DateTimeValue,B.DateTimeValue) DateTimeValue
FROM YourTable A
OUTER APPLY ( SELECT TOP 1 DateTimeValue
FROM YourTable
WHERE PersonID = A.PersonID
AND MonthYear < A.MonthYear
AND DateTimeValue IS NOT NULL
ORDER BY MonthYear DESC) B
Try this:
select t1.personid
, t1.monthyear
, datetimevalue = prev.datetimevalue
from t1
outer apply
(
select top 1 datetimevalue
, personid
, monthyear
from t1 prev
where prev.monthyear <= t1.monthyear
and prev.datetimevalue is not null
order by monthyear desc
) prev
order by t1.personid
, t1.monthyear
SQLFiddle demo.
Edited to change cross apply to outer apply, #Lamak had it right.
Does Sql Server allow nested SQL in the Select clause?
If it does:
select personId, monthYear,
(select T2.DateTimeValue from Tbl T2
where T2.monthYear=(select max(T3.monthYear) from Tbl T3
where T3.personid=T1.personId and T3.monthYear<=T1.monthYear
and T3.DateTimeValue is not null
)
)
from Tbl T1
i.e.
For each month, find the month less than equal to this month, but
with a not null DateTime;
Look up the DateTime value to the month found in the step above

Remove duplicate data in 'date-ranged' rows

I have a table like the following.
ID StartDate EndDate AttributeA AttributeB
-- --------- ------- ---------- ----------
1 1/1/2009 2/1/2009 0 C
1 2/1/2009 3/1/2009 1 C
1 3/1/2009 4/1/2009 1 C
2 1/1/2010 2/1/2010 0 D
2 3/1/2010 4/1/2010 1 D
The date range is used to know for what time period the rest of the Attributes were valid, the problem i have is that there are several consecutive time ranges where the Attributes ramain the same, what I would like is to obtain the same data but without the duplicate rows.
From the previous example, my expected end result would be like this:
ID StartDate EndDate AttributeA AttributeB
-- --------- ------- ---------- ----------
1 1/1/2009 2/1/2009 0 C
1 2/1/2009 4/1/2009 1 C
2 1/1/2010 2/1/2010 0 D
2 3/1/2010 4/1/2010 1 D
What I did was merge the 2nd and 3rd row into one (All attribute except the date were the same), but I kept the StartDate of the 2nd and the endDate of the 3rd row.
I first thought of grouping by the values obtaining the MAX and MIN like this
SELECT ID, MIN(StartDate), MAX(EndDate), attributeA, attributeB
FROM MyTable
Group BY ID, AttributeA, AttributeB
But as soon as I run it I realized that when the attributes change several times and go back to their original value I'd end up with overlapping intervals. I've been stuck for a while now trying to figure out how to fix this problem.
Here's an example of what I meant in my previous statement.
When the initial data looks like the following:
ID StartDate EndDate AttributeA AttributeB
-- --------- ------- ---------- ----------
1 1/1/2009 2/1/2009 0 C
1 2/1/2009 3/1/2009 0 D
1 3/1/2009 4/1/2009 0 D
1 4/1/2009 5/1/2009 1 D
1 6/1/2010 6/1/2009 0 D
Grouping the results would end up like the following
ID StartDate EndDate AttributeA AttributeB
-- --------- ------- ---------- ----------
1 1/1/2009 2/1/2009 0 C
1 2/1/2009 6/1/2009 0 D
1 4/1/2009 5/1/2009 1 D
And what I'd like to obtain is this
ID StartDate EndDate AttributeA AttributeB
-- --------- ------- ---------- ----------
1 1/1/2009 2/1/2009 0 C
1 2/1/2009 4/1/2009 0 D
1 4/1/2009 5/1/2009 1 D
1 6/1/2010 6/1/2009 0 D
Any help would be welcomed :)
EDIT: I'll be uploading some sample data soon to make my problem a bit easier to understand.
EDIT2: Here's a script with some of my data. From that sample what I'd like to obtain are the following rows.
ID StartDate EndDate A B C D E F
-- --------- ------- -- -- -- -- -- --
708513 1980-01-01 2006-07-23 15 ASDB A ACT 130 0
708513 2006-07-24 2009-12-08 15 ASDB A ACT 130 2
708513 2009-12-09 2010-01-12 0 ASDB A ACT 130 2
708513 2010-01-13 2079-05-30 15 ASDB A ACT 130 2
EDITED, following comments. Try:
;with cte as (
select m1.ID, m1.StartDate, m1.EndDate, m1.a, m1.b, m1.c, m1.d, m1.e, m1.f
from sampledata m1
where not exists
(select null from sampledata m0
where m1.ID = m0.ID and
m1.a = m0.a and
m1.b = m0.b and
m1.c = m0.c and
m1.d = m0.d and
m1.e = m0.e and
m1.f = m0.f and
dateadd(day, -1, m1.StartDate) = m0.EndDate)
union all
select m1.ID, m1.StartDate, m2.EndDate, m1.a, m1.b, m1.c, m1.d, m1.e, m1.f
from cte m1
join sampledata m2
on m1.ID = m2.ID and
m1.a = m2.a and
m1.b = m2.b and
m1.c = m2.c and
m1.d = m2.d and
m1.e = m2.e and
m1.f = m2.f and
dateadd(day, 1, m1.EndDate) = m2.StartDate)
select ID, StartDate, max(EndDate) EndDate, a, b, c, d, e, f
from cte
group by ID, StartDate, a, b, c, d, e, f
OPTION (MAXRECURSION 32767)
I made a version without recursion if someone is interested. I didn't really figure out how to add extra columns not used in comparison in the previous example.
IF OBJECT_ID('tempdb..#test') IS NOT NULL drop table #test
create table #test (
id int identity(1, 1)
, ship nvarchar(64)
, color nvarchar(16)
, [length] int
, height int
, [type] nvarchar(16)
, country nvarchar(16)
, StartDate date
)
insert into #test(ship, color, [length], height, [type], country, StartDate)
values
('Ship 1', 'Blue', 200, 13, 'sailboat', 'sweden', '2019-01-01')
, ('Ship 1', 'Blue', 200, 13, 'sailboat', 'sweden', '2019-02-01')
, ('Ship 1', 'Blue', 200, 13, 'sailboat', 'sweden', '2019-03-01')
, ('Ship 1', 'Red', 200, 13, 'motorboat', 'sweden', '2019-11-01')
, ('Ship 1', 'Blue', 200, 13, 'sailboat', 'sweden', '2019-12-01')
, ('Ship 2', 'Green', 400, 27, 'RoRo', 'denmark', '2019-02-01')
;
with step1 as (
select t.*
, [EndDate] = dateadd(day, -1, lead(t.StartDate, 1, '9999-12-31') over(partition by t.ship order by t.StartDate))
from #test t
where 1 = 1
)
, step2 as (
select t.*
-- Check if preceeding row with same attribute has enddate between this startdate
, [IdenticalPreceeding] = case
when t.StartDate = dateadd(day, 1, lag(t.EndDate, 1, '1900-01-01') over (partition by t.ship, t.color, t.[length], t.height, t.[type], t.country order by t.Startdate)) then 1
else 0
end
from step1 t
)
select t.*
, [EndDateFinal] = dateadd(day, -1, lead(t.StartDate, 1, '9999-12-31') over(partition by t.ship order by t.StartDate))
from step2 t
where 1 = 1
-- Remove rows with identical preceeders
and t.IdenticalPreceeding = 0
order by t.ship
, t.StartDate