Finding the missing dates between two date ranges in SQL - sql

I have a table like
ID StartDate EndDate
AAA 2017-03-17 00:00:00.000 2017-03-19 00:00:00.000
BB 2017-06-20 00:00:00.000 2017-06-25 00:00:00.000
CC 2017-05-13 00:00:00.000 2017-05-17 00:00:00.000
DD 2017-06-20 00:00:00.000 2017-05-27 00:00:00.000
EE 2017-03-01 00:00:00.000 2017-03-05 00:00:00.000
FF 2017-08-07 00:00:00.000 2017-08-11 00:00:00.000
i need the missing dates in between these ranges and the output table should be like
ID Date
AAA 2017-03-17 00:00:00.000 -- Start date for AAA
AAA 2017-03-18 00:00:00.000
AAA 2017-03-19 00:00:00.000 -- End date for AAA
BB 2017-06-20 00:00:00.000 -- start date for BB
BB 2017-06-21 00:00:00.000
BB 2017-06-22 00:00:00.000
BB 2017-06-23 00:00:00.000
BB 2017-06-24 00:00:00.000
BB 2017-06-25 00:00:00.000 -- End date for BB

You need to add loop to get dates between start and end dates , Example :
DECLARE #table table (ID Varchar(50), StartDate datetime,EndDate datetime)
insert into #table values ('AAA','2017-03-17 00:00:00.000',' 2017-03-19 00:00:00.000')
insert into #table values ('BB','2017-06-20 00:00:00.000 ',' 2017-06-25 00:00:00.000')
insert into #table values ('CC','2017-05-13 00:00:00.000 ',' 2017-05-17 00:00:00.000')
insert into #table values ('DD','2017-06-20 00:00:00.000 ',' 2017-05-27 00:00:00.000')
insert into #table values ('EE','2017-03-01 00:00:00.000 ',' 2017-03-05 00:00:00.000')
insert into #table values ('FF','2017-08-07 00:00:00.000 ',' 2017-08-11 00:00:00.000')
SELECT * FROM #table
SELECT id, StartDate FROM #table WHERE id='AAA'
union all
SELECT id, Dateadd(day,1,startdate) AS date FROM #table WHERE id='AAA' AND Dateadd(day,1,startdate)<EndDate
union all
SELECT id, EndDate FROM #table WHERE id='AAA'
union all
SELECT id, StartDate FROM #table WHERE id='BB'
union all
SELECT id, Dateadd(day,1,startdate) AS date FROM #table WHERE id='BB' AND Dateadd(day,1,startdate)<EndDate
union all
SELECT id, EndDate FROM #table WHERE id='BB'
union all
SELECT id, StartDate FROM #table WHERE id='CC'
union all
SELECT id, Dateadd(day,1,startdate) AS date FROM #table WHERE id='CC' AND Dateadd(day,1,startdate)<EndDate
union all
SELECT id, EndDate FROM #table WHERE id='CC'
union all
SELECT id, StartDate FROM #table WHERE id='DD'
union all
SELECT id, Dateadd(day,1,startdate) AS date FROM #table WHERE id='DD' AND Dateadd(day,1,startdate)<EndDate
union all
SELECT id, EndDate FROM #table WHERE id='DD'
union all
SELECT id, StartDate FROM #table WHERE id='EE'
union all
SELECT id, Dateadd(day,1,startdate) AS date FROM #table WHERE id='EE' AND Dateadd(day,1,startdate)<EndDate
union all
SELECT id, EndDate FROM #table WHERE id='EE'
union all
SELECT id, StartDate FROM #table WHERE id='FF'
union all
SELECT id, Dateadd(day,1,startdate) AS date FROM #table WHERE id='FF' AND Dateadd(day,1,startdate)<EndDate
union all
SELECT id, EndDate FROM #table WHERE id='FF'
Output:
id StartDate
AAA 2017-03-17 00:00:00.000
AAA 2017-03-18 00:00:00.000
AAA 2017-03-19 00:00:00.000
BB 2017-06-20 00:00:00.000
BB 2017-06-21 00:00:00.000
BB 2017-06-25 00:00:00.000
CC 2017-05-13 00:00:00.000
CC 2017-05-14 00:00:00.000
CC 2017-05-17 00:00:00.000
DD 2017-06-20 00:00:00.000
DD 2017-05-27 00:00:00.000
EE 2017-03-01 00:00:00.000
EE 2017-03-02 00:00:00.000
EE 2017-03-05 00:00:00.000
FF 2017-08-07 00:00:00.000
FF 2017-08-08 00:00:00.000
FF 2017-08-11 00:00:00.000

First, i created a calendar table based on your MIN and MAX date to get all the dates involved. Then i joined it to your table.
DECLARE #calendar AS TABLE ([Date] DATETIME)
DECLARE #maxDate AS DATETIME = (SELECT CASE WHEN MAX(StartDate) > MAX(EndDate)
THEN MAX(StartDate)
ELSE MAX(EndDate)
END FROM #YourTable)
DECLARE #minDate AS DATETIME = (SELECT CASE WHEN MIN(StartDate) < MIN(EndDate)
THEN MIN(StartDate)
ELSE MIN(EndDate)
END FROM #YourTable)
WHILE (#minDate < #maxDate)
BEGIN
INSERT INTO #calendar
VALUES (#minDate)
SET #minDate = DATEADD(DAY, 1, #minDate)
END
SELECT [Id], a.[Date]
FROM (Select [Date] FROM #calendar) a
LEFT JOIN #YourTable ON [Date] BETWEEN [StartDate] AND [EndDate]
WHERE [Id] IS NOT NULL

CREATE TABLE t
(
ID NVARCHAR(5) NOT NULL ,
StartDate DATETIME NOT NULL ,
EndDate DATETIME NOT NULL
);
GO
INSERT INTO dbo.t
( ID, StartDate, EndDate )
VALUES ( N'AAA', '2017-03-17 00:00:00.000', '2017-03-19 00:00:00.000' ),
( N'BB', '2017-06-20 00:00:00.000', '2017-06-25 00:00:00.000' ),
( N'CC', '2017-05-13 00:00:00.000', '2017-05-17 00:00:00.000' ),
( N'DD', '2017-06-20 00:00:00.000', '2017-05-27 00:00:00.000' ),
( N'EE', '2017-03-01 00:00:00.000', '2017-03-05 00:00:00.000' ),
( N'FF', '2017-08-07 00:00:00.000', '2017-08-11 00:00:00.000' );
WITH cte
AS ( SELECT ID ,
StartDate
FROM dbo.t
UNION ALL
SELECT cte.ID ,
DATEADD(DAY, 1, cte.StartDate)
FROM cte
INNER JOIN dbo.t ON t.ID = cte.ID
WHERE cte.StartDate < EndDate
)
SELECT cte.ID ,
cte.StartDate
FROM cte
ORDER BY cte.ID ,
cte.StartDate;
Result:
ID StartDate
----- -----------------------
AAA 2017-03-17 00:00:00.000
AAA 2017-03-18 00:00:00.000
AAA 2017-03-19 00:00:00.000
BB 2017-06-20 00:00:00.000
BB 2017-06-21 00:00:00.000
BB 2017-06-22 00:00:00.000
BB 2017-06-23 00:00:00.000
BB 2017-06-24 00:00:00.000
BB 2017-06-25 00:00:00.000
CC 2017-05-13 00:00:00.000
CC 2017-05-14 00:00:00.000
CC 2017-05-15 00:00:00.000
CC 2017-05-16 00:00:00.000
CC 2017-05-17 00:00:00.000
DD 2017-06-20 00:00:00.000
EE 2017-03-01 00:00:00.000
EE 2017-03-02 00:00:00.000
EE 2017-03-03 00:00:00.000
EE 2017-03-04 00:00:00.000
EE 2017-03-05 00:00:00.000
FF 2017-08-07 00:00:00.000
FF 2017-08-08 00:00:00.000
FF 2017-08-09 00:00:00.000
FF 2017-08-10 00:00:00.000
FF 2017-08-11 00:00:00.000

Related

SQL expand datefrom and dateto span of multiple years to multiple rows

I have the following input table with an id and start and enddate. I want to expand this to multiple rows when start and enddate span over multiple years, capping on the end of the year.
drop table if exists #policies;
create table #policies (
id int,
[start_date] datetime,
end_date datetime
);
insert into #policies (id, [start_date], end_date)
values
(1, '2019-01-01', '2021-12-31'),
(2, '2018-01-01', '2020-12-31'),
(3, '2011-01-01', '2013-12-31');
select * from #policies order by [id];
id start_date end_date
1 2019-01-01 00:00:00.000 2021-12-31 00:00:00.000
2 2018-01-01 00:00:00.000 2020-12-31 00:00:00.000
3 2011-01-01 00:00:00.000 2013-12-31 00:00:00.000
Expexted result:
drop table if exists #policies_expected;
create table #policies_expected (
id int,
[start_date] datetime,
end_date datetime
);
insert into #policies_expected (id, [start_date], end_date)
values
(1, '2019-01-01', '2019-12-31'),
(1, '2020-01-01', '2020-12-31'),
(1, '2021-01-01', '2021-12-31'),
(2, '2018-01-01', '2018-12-31'),
(2, '2019-01-01', '2019-12-31'),
(2, '2020-01-01', '2020-12-31'),
(3, '2011-01-01', '2011-12-31'),
(3, '2012-01-01', '2012-12-31'),
(3, '2013-01-01', '2013-12-31');
select * from #policies_expected order by [id], start_date
id start_date end_date
1 2019-01-01 00:00:00.000 2019-12-31 00:00:00.000
1 2020-01-01 00:00:00.000 2020-12-31 00:00:00.000
1 2021-01-01 00:00:00.000 2021-12-31 00:00:00.000
2 2018-01-01 00:00:00.000 2018-12-31 00:00:00.000
2 2019-01-01 00:00:00.000 2019-12-31 00:00:00.000
2 2020-01-01 00:00:00.000 2020-12-31 00:00:00.000
3 2011-01-01 00:00:00.000 2011-12-31 00:00:00.000
3 2012-01-01 00:00:00.000 2012-12-31 00:00:00.000
3 2013-01-01 00:00:00.000 2013-12-31 00:00:00.000
I tried to solve this with a recursive cte, which worked for one row:
with recursive cte(id, start_date, end_date) as (
select
id,
start_date,
dateadd(day, -1, dateadd(year, 1, start_date)) as end_date
from
#policies
where
id = 1 -- this filter is needed to make it work for one id
union all
select
id,
dateadd(year, 1, start_date) as start_date,
dateadd(day, -1, dateadd(year, 2, start_date)) as end_date
from
cte
where
start_date < dateadd(year, -1, (select max(end_date) from #policies where id=1))
)
select * from cte;
id start_date end_date
1 2019-01-01 00:00:00.000 2019-12-31 00:00:00.000
1 2020-01-01 00:00:00.000 2020-12-31 00:00:00.000
1 2021-01-01 00:00:00.000 2021-12-31 00:00:00.000
The problem here is
select max(end_date) from #policies where id=1
I am not sure how to do this per id, if I would remove the where clause in my solution, it would take the max enddate for the whole table. This needs to happen per id.
How can I solve this, I am open for other solutions as well.

SQL - Generate bi-weekly end date on custom start date

I want to get a custom Fort Night period based on a given start date.
I have a table that looks like this:
IF OBJECT_ID('tempdb..#tbl1') IS NOT NULL DROP TABLE #tbl1
SET DATEFIRST 1
DECLARE #StartDateTime DATETIME
DECLARE #EndDateTime DATETIME
SET #StartDateTime = '2016-09-03'
SET #EndDateTime = '2017-01-28';
WITH DateRange(DateData) AS
(
SELECT #StartDateTime as Date
UNION ALL
SELECT DATEADD(d,1,DateData)
FROM DateRange
WHERE DateData < #EndDateTime
)
SELECT ROW_NUMBER() OVER(ORDER BY DateData ASC) As ROWNum,DateData AS Date1
into #tbl1
FROM DateRange
OPTION (MAXRECURSION 0)
GO
SELECT top 10 * FROM #tbl1
Date1
2016-09-09 00:00:00.000
2016-09-10 00:00:00.000
2016-09-11 00:00:00.000
2016-09-12 00:00:00.000
2016-09-13 00:00:00.000
2016-09-14 00:00:00.000
2016-09-15 00:00:00.000
2016-09-16 00:00:00.000
2016-09-17 00:00:00.000
2016-09-18 00:00:00.000
2016-09-19 00:00:00.000
2016-09-20 00:00:00.000
2016-09-21 00:00:00.000
2016-09-22 00:00:00.000
I want to say the the first date of my bi-weekly period is 2016-09-09 and it ends 2016-09-22. How do I get bi-weekly end date for each of those dates.
So I want it to look like
Date1 FortNightEndDate
2016-09-09 00:00:00.000 2016-09-22 00:00:00.000
2016-09-10 00:00:00.000 2016-09-22 00:00:00.000
2016-09-11 00:00:00.000 2016-09-22 00:00:00.000
2016-09-12 00:00:00.000 2016-09-22 00:00:00.000
2016-09-13 00:00:00.000 2016-09-22 00:00:00.000
2016-09-14 00:00:00.000 2016-09-22 00:00:00.000
2016-09-15 00:00:00.000 2016-09-22 00:00:00.000
2016-09-16 00:00:00.000 2016-09-22 00:00:00.000
2016-09-17 00:00:00.000 2016-09-22 00:00:00.000
2016-09-18 00:00:00.000 2016-09-22 00:00:00.000
2016-09-19 00:00:00.000 2016-09-22 00:00:00.000
2016-09-20 00:00:00.000 2016-09-22 00:00:00.000
2016-09-21 00:00:00.000 2016-09-22 00:00:00.000
2016-09-22 00:00:00.000 2016-09-22 00:00:00.000
I'm using SQL Server 2005.
ANSWER:
I was able to solve it using the following code. Essentially I just created 3 tables:
StartDates
EndDates
InbetweenDates
The Start/EndDates tables had just the start and End of my 2 week period and an ID (Row Number)
The InbetweenDates table had all the dates between the 2 dates and also had a ID column but instead of going up 1 every row, it went up 1 every 14 rows.
Then I just joined the 3 tables. Essentially, the Start/EndDates tables were lookup tables.
I got the RowNumber on every 14 days code from here.
-- BEtween Dates
IF OBJECT_ID('tempdb..#BetweenDates') IS NOT NULL DROP TABLE #BetweenDates
DECLARE #StartDateTime DATETIME
DECLARE #EndDateTime DATETIME
SET #StartDateTime = '2016-09-09'
SET #EndDateTime = '2017-04-30';
WITH DateRange(DateData) AS
(
SELECT #StartDateTime as Date
UNION ALL
SELECT DATEADD(d,1,DateData)
FROM DateRange
WHERE DateData < #EndDateTime
)
SELECT
DateData
into #BetweenDates
FROM DateRange
OPTION (MAXRECURSION 0)
GO
select
(case when convert(int, (ROW_NUMBER() OVER (Order by (select 0)) % 14))=0 then 0 else 1 end)
+ convert(int, (ROW_NUMBER() OVER (Order by (select 0)) / 14)) as ID
,DateData
INTO #BetweenDates_ID
from #BetweenDates
-- Start Dates
IF OBJECT_ID('tempdb..#StartDates') IS NOT NULL DROP TABLE #StartDates
DECLARE #StartDateTime DATETIME
DECLARE #EndDateTime DATETIME
SET #StartDateTime = '2016-09-09'
SET #EndDateTime = '2017-04-30';
WITH DateRange(DateData) AS
(
SELECT #StartDateTime as Date
UNION ALL
SELECT DATEADD(d,14,DateData)
FROM DateRange
WHERE DateData < #EndDateTime
)
SELECT ROW_NUMBER() OVER(ORDER BY DateData ASC) As ID,DateData
into #StartDates
FROM DateRange
OPTION (MAXRECURSION 0)
GO
-- End Dates
IF OBJECT_ID('tempdb..#EndDates') IS NOT NULL DROP TABLE #EndDates
DECLARE #StartDateTime DATETIME
DECLARE #EndDateTime DATETIME
SET #StartDateTime = '2016-09-22'
SET #EndDateTime = '2017-04-30';
WITH DateRange(DateData) AS
(
SELECT #StartDateTime as Date
UNION ALL
SELECT DATEADD(d,14,DateData)
FROM DateRange
WHERE DateData < #EndDateTime
)
SELECT ROW_NUMBER() OVER(ORDER BY DateData ASC) As ID,DateData
into #EndDates
FROM DateRange
OPTION (MAXRECURSION 0)
GO
--SELECT * FROM #StartDates
--SELECT * FROM #EndDates
--SELECT * FROM #BetweenDates_ID
SELECT
st.DateData AS StartDate
,ed.DateData AS EndDate
,bd.DateData AS BetweenDate
FROM
#StartDates st
JOIN
#EndDates ed
ON st.ID = ed.ID
LEFT JOIN
#BetweenDates_ID bd
ON st.ID = bd.ID
Try this:
SELECT Date1,
DATEADD(DD, -1, DATEADD(WW,2,Date1)) AS FortNightEndDate
FROM #tbl1

How To find attendance Mispunch in sql

I have a table tbl_attendance in SQL Server with data is in this format
card_no adate time
-----------------------------------------
13 2016-08-01 2016-08-01 09:30:00
13 2016-08-01 2016-08-01 11:00:00
13 2016-08-01 2016-08-01 12:00:00
13 2016-08-01 2016-08-01 15:00:00
13 2016-08-01 2016-08-01 16:00:00
13 2016-08-02 2016-08-02 09:30:00
but when I execute my query, I want to get results in this format
card_no adate time_in time_in
----------------------------------------------------------------
13 2016-08-01 2016-08-01 09:30:00 2016-08-01 11:00:00
13 2016-08-01 2016-08-01 12:00:00 2016-08-01 15:00:00
13 2016-08-01 2016-08-01 16:00:00 null
13 2016-08-02 2016-08-02 09:30:00 null
Please help as soon as possible
Try this trick
;WITH cte
AS (SELECT *,
((Row_number()OVER(partition BY [adate] ORDER BY [time])-1)%2) + 1 AS seq_no,
((Row_number()OVER(partition BY [adate] ORDER BY [time])-1)/2) + 1 rang_no
FROM Yourtable)
SELECT [card_no],
[adate],
time_in = Min(CASE WHEN seq_no = 1 THEN [time] END),
time_in = Min(CASE WHEN seq_no = 2 THEN [time] END)
FROM cte
GROUP BY [card_no],
[adate],
rang_no
Demo
Schema Setup
IF Object_id('tempdb.dbo.#Table1') is not null
DROP TABLE #Table1
CREATE TABLE #Table1
([card_no] int, [adate] date, [time] datetime);
Sample Data
INSERT INTO #Table1
([card_no], [adate], [time])
VALUES
(13, '2016-08-01 00:00:00', '2016-08-01 09:30:00'),
(13, '2016-08-01 00:00:00', '2016-08-01 11:00:00'),
(13, '2016-08-01 00:00:00', '2016-08-01 12:00:00'),
(13, '2016-08-01 00:00:00', '2016-08-01 15:00:00'),
(13, '2016-08-01 00:00:00', '2016-08-01 16:00:00'),
(13, '2016-08-02 00:00:00', '2016-08-02 09:30:00');
Query
;WITH cte
AS (SELECT *,
((Row_number()OVER(partition BY [adate] ORDER BY [time])-1)%2) + 1 AS seq_no,
((Row_number()OVER(partition BY [adate] ORDER BY [time])-1)/2) + 1 rang_no
FROM #Table1)
SELECT [card_no],
[adate],
time_in = Min(CASE WHEN seq_no = 1 THEN [time] END),
time_in = Min(CASE WHEN seq_no = 2 THEN [time] END)
FROM cte
GROUP BY [card_no],
[adate],
rang_no
Result:
card_no adate time_in time_in
------ ---------- ----------------------- -----------------------
13 2016-08-01 2016-08-01 09:30:00.000 2016-08-01 11:00:00.000
13 2016-08-01 2016-08-01 12:00:00.000 2016-08-01 15:00:00.000
13 2016-08-01 2016-08-01 16:00:00.000 NULL
13 2016-08-02 2016-08-02 09:30:00.000 NULL
Another way with OUTER APPLY (is used to get next row with time > than in current row) and ROW_NUMBER (with %2 to get only odd rows):
SELECT t.card_no,
t.adate,
t.[time],
t.time_in
FROM (
SELECT y.*,
p.[time] as time_in,
ROW_NUMBER() OVER (PARTITION BY y.card_no, y.adate ORDER BY y.[time])%2 as seq
FROM YourTable y
OUTER APPLY (
SELECT TOP 1 *
FROM YourTable
WHERE [time] > y.[time] and [adate] = y.adate
ORDER BY [time] ASC
) p
) as t
WHERE t.seq = 1
ORDER BY [time]
Output:
card_no adate time time_in
13 2016-08-01 2016-08-01 09:30:00 2016-08-01 11:00:00
13 2016-08-01 2016-08-01 12:00:00 2016-08-01 15:00:00
13 2016-08-01 2016-08-01 16:00:00 NULL
13 2016-08-02 2016-08-02 09:30:00 NULL

Find range of dates within same column

I have a data set, which looks like this:
ResourceID RequirementId ProjectID Startdate EndDate BillingPercentage
-------------------- -------------------- -------------------- ----------------------- ----------------------- ---------------------------------------
1 5066 7505 2015-09-15 00:00:00.000 2015-09-30 00:00:00.000 50
2 4748 7499 2015-09-10 00:00:00.000 2015-09-20 00:00:00.000 50
I want to calculate range and corresponding billing % for that particular month my query is:
INSERT INTO #DateTimeline
SELECT #MonthStartDate AS OSTARTDATE,#MonthEndDate AS OENDDATE,0
INSERT INTO #DateTimeline
SELECT Startdate AS OSTARTDATE,EndDate AS OENDDATE,BillingPercentage From #RESOURCE_UNBILLED Order by Startdate
INSERT INTO #DateTimeline
SELECT EndDate AS OSTARTDATE,EndDate AS OENDDATE,BillingPercentage From #RESOURCE_UNBILLED Order by Startdate
And data looks like following:
SerialNo OSTARTDATE OENDDATE BillingPercentage
----------- ----------------------- ----------------------- ---------------------------------------
1 2015-09-01 00:00:00.000 2015-09-30 00:00:00.000 0
2 2015-09-10 00:00:00.000 2015-09-20 00:00:00.000 50
3 2015-09-15 00:00:00.000 2015-09-30 00:00:00.000 50
4 2015-09-20 00:00:00.000 2015-09-20 00:00:00.000 50
5 2015-09-30 00:00:00.000 2015-09-30 00:00:00.000 50
I want to retrive data like following
OSTARTDATE OENDDATE BillingPercentage
----------- ----------------------- ----------------------- ---------------------------------------
2015-09-01 00:00:00.000 2015-09-10 00:00:00.000 0
2015-09-10 00:00:00.000 2015-09-15 00:00:00.000 50
2015-09-15 00:00:00.000 2015-09-20 00:00:00.000 100
2015-09-20 00:00:00.000 2015-09-30 00:00:00.000 50
Please suggest how can I get this also can I use pivot here?
Use a table variable to store your #dateStamps with columns: SerialNo, OSTARTDATE and OENDDATE.
Try this query:
SELECT d.SerialNo, d.OSTARTDATE, d.OENDDATE
, ( SELECT SUM(t.BillingPercentage)
FROM yourTable t
WHERE d.OENDDATE BETWEEN t.Startdate AND t.EndDate
OR d.OSTARTDATE BETWEEN t.Startdate AND t.EndDate
OR (d.OSTARTDATE > t.Startdate AND d.OENDDATE < t.EndDate)
) AS BillingPercentage
FROM
#dateStamps d
My complete code is:
DECLARE #DatePart as int = 5
;WITH dateStamps AS (
SELECT 1 As SerialNo, CAST('2015-' + CONVERT(varchar, MONTH(MIN(t.Startdate))) + '-01 00:00:00.000' As datetime) AS OSTARTDATE
, CAST('2015-' + CONVERT(varchar, MONTH(MIN(t.Startdate))) + '-01 00:00:00.000' As datetime) + (#DatePart - 1) AS OENDDATE
FROM yourTable t
UNION ALL
SELECT ds.SerialNo + 1, ds.OSTARTDATE + #DatePart, ds.OSTARTDATE + (#DatePart * 2 - 1)
FROM dateStamps ds
WHERE MONTH(OSTARTDATE + #DatePart) <= MONTH(ds.OSTARTDATE)
)
SELECT d.SerialNo, d.OSTARTDATE, d.OENDDATE
, ( SELECT SUM(t.BillingPercentage)
FROM t
WHERE d.OENDDATE BETWEEN t.Startdate AND t.EndDate
OR d.OSTARTDATE BETWEEN t.Startdate AND t.EndDate
OR (d.OSTARTDATE > t.Startdate AND d.OENDDATE < t.EndDate)
) AS BillingPercentage
FROM
dateStamps d

Problem in Start And End Dates using CTE

I have the below input
ID Activity Date
1 gardening 2011-01-01 00:00:00.000
1 gardening 2011-02-01 00:00:00.000
2 cooking 2011-03-01 00:00:00.000
2 cooking 2011-04-01 00:00:00.000
2 cooking 2011-05-01 00:00:00.000
1 gardening 2011-06-01 00:00:00.000
1 gardening 2011-07-01 00:00:00.000
The ddl is as under
Declare #t table(ID int,Activity Varchar(50),[Date] DATETIME)
Insert into #t Select 1,'gardening','01/01/2011' union all Select 1,'gardening','02/01/2011'
union all Select 2,'cooking','03/01/2011' union all Select 2,'cooking','04/01/2011'
union all Select 2,'cooking','05/01/2011' union all Select 1,'gardening','06/01/2011'
union all Select 1,'gardening','07/01/2011'
select * from #t
Expected output
ID ACTIVITY INITIAL_DATE END_DATE
1 gardening 01/01/2011 02/01/2011
1 gardening 02/01/2011 06/01/2011
1 gardening 06/01/2011 07/01/2011
2 cooking 03/01/2011 04/01/2011
2 cooking 04/01/2011 05/01/2011
So far I have done
;with cte as(Select Rn= ROW_NUMBER() Over(order by ID,[Date]),* from #t)
,cte2 as(
Select Rn
,ID,Activity,InitialDate =[Date],EndDate = [Date]
from cte where Rn =1
union all
Select c1.Rn
,c1.ID,c1.Activity,c1.Date,c1.Date
from cte2 c2
join cte c1
on c1.rn = c2.Rn+1
)
select ID,Activity,InitialDate,EndDate from cte2
but the output is not correct
ID Activity InitialDate EndDate
1 gardening 2011-01-01 00:00:00.000 2011-01-01 00:00:00.000
1 gardening 2011-02-01 00:00:00.000 2011-02-01 00:00:00.000
1 gardening 2011-06-01 00:00:00.000 2011-06-01 00:00:00.000
1 gardening 2011-07-01 00:00:00.000 2011-07-01 00:00:00.000
2 cooking 2011-03-01 00:00:00.000 2011-03-01 00:00:00.000
2 cooking 2011-04-01 00:00:00.000 2011-04-01 00:00:00.000
2 cooking 2011-05-01 00:00:00.000 2011-05-01 00:00:00.000
Help needed
;with cte as
(
select *,
row_number() over(partition by ID order by [Date]) as rn
from #t
)
select C1.ID,
C1.Activity,
C1.[Date] as INITIAL_DATE,
C2.[Date] as END_DATE
from cte as C1
inner join cte as C2
on C1.ID = C2.ID and
C1.rn + 1 = C2.rn
order by C1.ID, C1.[Date]
try this -
in oracle it is giving desired output..
please check for respective sql server function for lead () in oracle database
with cte as(Select * from #t)
(
SELECT * from
(
SELECT id,activity,
lead(date) over(partition be id,activity order by date desc) INITIAL_DATE,
date END_DATE
from cte
order by id,activity,date
)
WHERE INITIAL_DATE is not null
)