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

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.

Related

Function that returns MAX OR MIN dates based on ID count

I have a task in SQL Server where I need to return the RESULT_DATE column using ID, PRODUCT_ID and DATE columns. Task criteria:
If DATE column is filled once for each PRODUCT_ID then I need to return the only date (like for PRODUCT_ID 1 and 3). Let`s say its MIN date.
If DATE column is filled more than one time (like for PRODUCT_ID 2) then I need to return the next filled DATE row.
Data:
CREATE TABLE #temp (
ID INT,
PRODUCT_ID INT,
[DATE] DATETIME
)
INSERT #temp (ID, PRODUCT_ID, DATE) VALUES
(1, 1, '2008-04-24 00:00:00.000'),
(2, 1, NULL),
(3, 2, '2015-12-09 00:00:00.000'),
(4, 2, NULL),
(5, 2, NULL),
(6, 2, '2022-01-01 13:06:45.253'),
(7, 2, NULL),
(8, 2, '2022-01-19 13:06:45.253'),
(9, 3, '2018-04-25 00:00:00.000'),
(10,3, NULL),
(11,3, NULL)
ID
PRODUCT_ID
DATE
RESULT_DATE
1
1
2008-04-24 00:00:00.000
2008-04-24 00:00:00.000
2
1
NULL
2008-04-24 00:00:00.000
3
2
2015-12-09 00:00:00.000
2022-01-01 13:06:45.253
4
2
NULL
2022-01-01 13:06:45.253
5
2
NULL
2022-01-01 13:06:45.253
6
2
2022-01-01 13:06:45.253
2022-01-19 13:06:45.253
7
2
NULL
2022-01-19 13:06:45.253
8
2
2022-01-19 13:06:45.253
2022-01-19 13:06:45.253
9
3
2018-04-25 00:00:00.000
2018-04-25 00:00:00.000
10
3
NULL
2018-04-25 00:00:00.000
11
3
NULL
2018-04-25 00:00:00.000
I have tried different techniques, for example using LEAD and LAG SQL function combinations. The latest script: (However, still not working)
SELECT
COALESCE(DATE,
CAST(
SUBSTRING(
MAX(CAST(DATE AS BINARY(4)) + CAST(DATE AS BINARY(4))) OVER ( PARTITION BY PRODUCT_ID ORDER BY DATE ROWS UNBOUNDED PRECEDING)
,5,4)
AS INT)
) AS RESULT_DATE,
*
FROM TABLE
You can use a CTE, Select all rows with a non-NULL Date giving each a row_number, then use a second CTE to fetch all rows from the first CTE equivalent to the date with the largest row number per product_id that is less than 3. Finally join this CTE to the original table to supply the 2nd Date to each row:
Set Up
CREATE TABLE #temp (
ID INT,
PRODUCT_ID INT,
MyDATE DATETIME
)
INSERT #temp (ID, PRODUCT_ID, MyDate)
VALUES
(1, 1, '2008-04-24 00:00:00.000'),
(2, 1, NULL),
(3, 2, '2015-12-09 00:00:00.000'),
(4, 2, NULL),
(5, 2, NULL),
(6, 2, '2022-01-01 13:06:45.253'),
(7, 2, NULL),
(8, 2, '2022-01-19 13:06:45.253'),
(9, 3, '2018-04-25 00:00:00.000'),
(10,3, NULL),
(11,3, NULL);
Query:
;WITH CTE
AS
(
SELECT ID, Product_ID, MyDate,
ROW_NUMBER() OVER (PARTITION BY Product_ID ORDER BY Id) AS rn
from #temp
WHERE MyDate IS NOT NULL
),
CTE2
AS
(
SELECT *
FROM CTE C1
WHERE C1.rn < 3
AND
C1.rn =
(SELECT MAX(rn) FROM CTE WHERE Product_Id = C1.Product_Id AND rn<3)
)
SELECT T.Id, T.Product_Id, T.MyDate, C.MyDate As Result_date
FROM #temp T
INNER JOIN CTE2 C
ON T.Product_Id = C.Product_Id
ORDER BY T.Id;
Results:
Id Product_Id MyDate Result_Date
1 1 2008-04-24 00:00:00.000 2008-04-24 00:00:00.000
2 1 NULL 2008-04-24 00:00:00.000
3 2 2015-12-09 00:00:00.000 2022-01-01 13:06:45.253
4 2 NULL 2022-01-01 13:06:45.253
5 2 NULL 2022-01-01 13:06:45.253
6 2 2022-01-01 13:06:45.253 2022-01-01 13:06:45.253
7 2 NULL 2022-01-01 13:06:45.253
8 2 2022-01-19 13:06:45.253 2022-01-01 13:06:45.253
9 3 2018-04-25 00:00:00.000 2018-04-25 00:00:00.000
10 3 NULL 2018-04-25 00:00:00.000
11 3 NULL 2018-04-25 00:00:00.000

Split DATEDIFF into separate months

I currently have an issue whereby I am doing DATEDIFF in minutes between a start date and end date, however I when this date goes over into a new month I need the figures to be separate for each month.
Please see example data (both Text and Image view);
SELECT [BookingNum]
,[StartDate]
,[EndDate]
,[Location]
,DATEPART(m,startdate) AS [Month]
,DATEDIFF(MINUTE,StartDate,EndDate) AS [Minutes]
FROM [Test].[dbo].[Booking]
BookingNum StartDate EndDate Location Month Minutes
1 2019-02-05 12:54:00.000 2019-02-08 15:00:00.000 Area 1 2 4446
2 2019-05-02 10:41:00.000 2019-05-10 12:39:00.000 Area 2 5 11638
3 2019-06-01 10:30:00.000 2019-06-04 09:25:00.000 Area 3 6 4255
4 2019-02-02 09:41:00.000 2019-04-20 11:54:00.000 Area 1 2 111013
5 2019-03-29 19:09:00.000 2019-04-02 10:41:00.000 Area 3 3 5252
For rows 4 & 5 there would need to be additional rows as they go across multiple months.
Example for the data in row 4, I would want to see;
StartDate EndDate Location Month Minutes
2019-02-02 09:41:00.000 2019-02-28 23:59:00.000 Area 1 2 38298
2019-03-01 00:00:00.000 2019-03-31 23:59:00.000 Area 1 3 44639
2019-04-01 00:00:00.000 2019-04-20 23:59:00.000 Area 1 4 28074
This would then give me the total minutes for that month only between the start and end date.
Any help much appreciated.
Edit: Recursive CTE should do the trick! Basically, use recursion to keep getting the start date through the lesser of the EOM and the end date, until ultimately you reach the end date.
Fiddle
DECLARE #tbl TABLE (bookingnum INT, sd DATETIME, ed DATETIME)
INSERT INTO #tbl VALUES
(1, '2/5/2019 12:54 PM', '2/8/2019 3:00 PM'),
(2, '5/2/2019 10:41 AM', '5/10/2019 12:39 PM'),
(3, '6/1/2019 10:30 AM', '6/4/2019 9:25 AM'),
(4, '2/2/2019 9:41 AM', '5/20/2019 11:54 AM'),
(5, '3/29/2019 7:09 PM', '4/2/2019 10:41 AM')
;WITH cte AS (
SELECT bookingnum, sd, DATEADD(DAY, 1, EOMONTH(sd)) eom, ed,
CASE WHEN DATEADD(DAY, 1, EOMONTH(sd)) < ed THEN DATEADD(DAY, 1, EOMONTH(sd)) else ed END AS applied_ed
FROM #tbl
UNION ALL
SELECT bookingnum, applied_ed, DATEADD(DAY, 1, EOMONTH(applied_ed)) eom, ed,
CASE WHEN DATEADD(DAY, 1, EOMONTH(applied_ed)) < ed THEN DATEADD(DAY, 1, EOMONTH(applied_ed)) else ed END AS applied_ed
FROM cte
WHERE applied_ed < ed
)
SELECT bookingnum, sd, applied_ed AS ed, DATEDIFF(MINUTE, sd, applied_ed) minutes
FROM cte
ORDER BY bookingnum, sd
Returns:
bookingnum sd ed minutes
1 2019-02-05 12:54:00.000 2019-02-08 15:00:00.000 4446
2 2019-05-02 10:41:00.000 2019-05-10 12:39:00.000 11638
3 2019-06-01 10:30:00.000 2019-06-04 09:25:00.000 4255
4 2019-02-02 09:41:00.000 2019-03-01 00:00:00.000 38299
4 2019-03-01 00:00:00.000 2019-04-01 00:00:00.000 44640
4 2019-04-01 00:00:00.000 2019-05-01 00:00:00.000 43200
4 2019-05-01 00:00:00.000 2019-05-20 11:54:00.000 28074
5 2019-03-29 19:09:00.000 2019-04-01 00:00:00.000 3171
5 2019-04-01 00:00:00.000 2019-04-02 10:41:00.000 2081
This can be achieved using recursive CTE as follows. This calculates multiple months between startdate and enddate.
Fiddle: http://sqlfiddle.com/#!18/26568/4
create table #temp(
BookingNum int,
StartDate datetime,
EndDate datetime,
Location varchar(25),
)
insert into #temp
values(1,'2019-02-05 12:54:00','2019-02-08 15:00:00','Area 1'),
(2,'2019-05-02 10:41:00','2019-05-10 12:39:00','Area 2'),
(3,'2019-06-01 10:30:00','2019-06-04 09:25:00','Area 3'),
(4,'2019-02-02 09:41:00','2019-05-20 11:54:00','Area 1'),
(5,'2019-03-29 19:09:00','2019-04-02 10:41:00','Area 3')
;WITH cte AS
(
SELECT BookingNum,
StartDate,
CASE
WHEN DATEPART(m, EndDate) > DATEPART(m, startdate)
THEN DATEADD(s, -1, DATEADD(mm, DATEDIFF(m, 0, startdate) + 1, 0))
ELSE EndDate
END AS EndDate,
Location,
DATEPART(m, EndDate) - DATEPART(m, startdate) AS MonthDiff
FROM #temp
UNION ALL
SELECT cte.BookingNum,
CASE
WHEN cte.MonthDiff > 0
THEN DATEADD(month, DATEDIFF(month, 0, DATEADD(month, 1, cte.StartDate)), 0)
ELSE cte.StartDate
END AS startDate,
CASE
WHEN cte.MonthDiff > 0 AND DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, DATEADD(month, 1, cte.StartDate)) + 1, 0)) < t.EndDate
THEN DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, DATEADD(month, 1, cte.StartDate)) + 1, 0))
ELSE t.EndDate
END AS EndDate,
cte.Location,
(cte.MonthDiff - 1) MonthDiff
FROM cte
INNER JOIN #temp t ON cte.BookingNum = t.BookingNum
WHERE cte.MonthDiff > 0
)
SELECT BookingNum,
StartDate,
EndDate,
Location,
DATEPART(m, startdate) AS month,
DATEDIFF(minute, startdate, enddate) AS minutes
FROM cte
ORDER BY 1;
drop table #temp
Result:
BookingNum StartDate EndDate Location month minutes
----------- ----------------------- ----------------------- ------------------------- ----------- -----------
1 2019-02-05 12:54:00.000 2019-02-08 15:00:00.000 Area 1 2 4446
2 2019-05-02 10:41:00.000 2019-05-10 12:39:00.000 Area 2 5 11638
3 2019-06-01 10:30:00.000 2019-06-04 09:25:00.000 Area 3 6 4255
4 2019-02-02 09:41:00.000 2019-02-28 23:59:59.000 Area 1 2 38298
4 2019-03-01 00:00:00.000 2019-03-31 00:00:00.000 Area 1 3 43200
4 2019-04-01 00:00:00.000 2019-04-30 00:00:00.000 Area 1 4 41760
4 2019-05-01 00:00:00.000 2019-05-20 11:54:00.000 Area 1 5 28074
5 2019-03-29 19:09:00.000 2019-03-31 23:59:59.000 Area 3 3 3170
5 2019-04-01 00:00:00.000 2019-04-02 10:41:00.000 Area 3 4 2081
To achieve this you will need to create an additional table to join to that contains the months. You would then join to that table where the month of the date is between the dates in the calendar table, to do this you need to use a dateadd/datediff function to round your date to the first of the month e.g.: DATEADD(month, DATEDIFF(month, 0, StartDate),0). This works by calculating the difference in months between some random start date (in this case 0, I.e. 1/1/1900) and then adding those months back on to the start date.
Then you will need to round your start or end date up or down to the end of the month if they are not in the same month as the calendar table record, which will allow you to do a new calculation for the time.
The whole code would look something like this:
CREATE TABLE #MonthDate
(MonthDate date PRIMARY KEY);
INSERT INTO #MonthDate (MonthDate)
VALUES ('20190101'),('20190201'),('20190301'),('20190401'),('20190501'),('20190601');
WITH RoundedDates As
(SELECT b.StartDate,
B.EndDate,
DATEADD(month, DATEDIFF(month, 0, b.StartDate),0) AS RoundedStartDate,
DATEADD(month, DATEDIFF(month, 0, b.EndDate),0) AS RoundedEndDate
FROM Test.dbo.Booking AS b)
SELECT rd.StartDate
, rd.EndDate
, DATEDIFF(minute, CASE WHEN rd.RoundedStartDate = md.MonthDate THEN rd.StartDate ELSE md.MonthDate END, CASE WHEN rd.RoundedEndDate = md.MonthDate THEN rd.EndDate ELSE DATEADD(month,1,md.MonthDate) END) AS Minutes
FROM RoundedDates AS rd
INNER JOIN #MonthDate as md
ON md.MonthDate BETWEEN rd.RoundedStartDate AND rd.RoundedEndDate
http://sqlfiddle.com/#!18/70730/2

Finding the missing dates between two date ranges in 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

SQL query stuck - comparison on different lines

I m working on a very weird problem with SQL where I have to compare previous rows
Number start_date end_date
----- ------- ------------
1 2011-06-07 00:00:00.000 2011-07-10 00:00:00.000
2 2011-10-11 00:00:00.000 2011-10-11 00:00:00.000
3 2011-10-26 00:00:00.000 2011-10-29 00:00:00.000
4 2011-10-29 00:00:00.000 2011-11-15 00:00:00.000
Here , I have to compare the start_date and end_date on the two different line and create a view out of it.
(If the start_date is less than the previous end_date , then criteria is set to 1).
Well it should compare 2011-10-26 00:00:00.000 for 3 and 2011-10-27 00:00:00.000 on 2 for 30 days
Number start_date end_date Criteria
----- ----------- ---------------- ------------
1 2011-06-07 00:00:00.000 2011-07-10 00:00:00.000 0
2 2011-10-11 00:00:00.000 2011-10-11 00:00:00.000 0
3 2011-10-26 00:00:00.000 2011-10-29 00:00:00.000 1
4 2011-10-30 00:00:00.000 2011-11-15 00:00:00.000 1
I m confused how should I proceed with this.
Any help would be helpful !!!!
Thanks !!!
The most straightforward way to do this is to use a subquery:
select A.number, a.start_date, a.end_date,
CASE WHEN start_date < dateadd(d,30,(select TOP(1) b.end_date
from mytable B
where B.number < A.number
order by B.number desc)) then 1 else 0 end Criteria
from mytable A
Note: If the start date is the 29th day following the previous row's end date, Criteria becomes 1. By the 30th day onwards, it is 0. Tweak the 30 in the query as required.
Sample:
create table mytable (
Number int primary key,
start_date datetime,
end_date datetime);
insert mytable
select 1, '2011-06-07', '2011-07-10' union all
select 2, '2011-10-11', '2011-10-27' union all
select 3, '2011-10-26', '2011-10-29' union all
select 4, '2011-10-29', '2011-11-15'
Result:
number start_date end_date Criteria
1 2011-06-07 00:00:00.000 2011-07-10 00:00:00.000 0
2 2011-10-11 00:00:00.000 2011-10-27 00:00:00.000 0
3 2011-10-26 00:00:00.000 2011-10-29 00:00:00.000 1
4 2011-10-29 00:00:00.000 2011-11-15 00:00:00.000 0
Try using case like this:
create view vDates as
select Number,start_date,end_date,
case
when start_date<end_date
then 0
else 1
end as Criteria
from tab
SQL Fiddle Demo
A more readable way is create a function and send the correct dates:
Function:
create function [dbo].[CompareDates] (
#START_DATE datetime,
#PREVIOUS_END_DATE datetime
)
RETURNS int
AS
BEGIN
if #START_DATE < #PREVIOUS_END_DATE
return 1
return 0
END
Query (using subquery):
declare #dates table
(
number int,
start datetime,
end_date datetime
)
insert into #dates values
(1, '2011-06-07 00:00:00.000', '2011-07-10 00:00:00.000'),
(2, '2011-10-11 00:00:00.000', '2011-10-27 00:00:00.000'),
(3, '2011-10-26 00:00:00.000', '2011-10-29 00:00:00.000'),
(4, '2011-10-29 00:00:00.000', '2011-11-15 00:00:00.000')
select *, dbo.CompareDates(dates.end_date, dates.previous_end_date) from
(
select number, start, end_date,
(select TOP 1 end_date
from #dates d2
where d2.number < d1.number
order by d2.number desc) as previous_end_date
from #dates d1
) dates

how to display weekdays from below two days (Monday and Friday)?

how to display weekdays from below two days (Monday and Friday) Using SQL QUERY?
Date_From= 01/03/2011
Date_To =15/03/2011
I need output like below
Date_From Date_To
01/03/2011 01/03/2011
04/03/2011 04/03/2011 'Friday
05/03/2011 06/03/2011
07/03/2011 07/03/2011 'Monday
08/03/2011 10/03/2011
11/03/2011 11/03/2011 'Friday
12/03/2011 13/03/2011
14/03/2011 14/03/2011 'Monday
15/03/2011 15/03/2011
hoping your help
select
t1.Date_From,
t1.Date_To,
case when DATENAME(dw,t1.Date_to) IN ('friday','monday') THEN DATENAME(dw,t1.Date_to) else NULL END
from table t1
This is using Oracle. I can get the 15th to show up if I use Oracle analytic functions, but I don't know of a portable way to get the result in one row to depend on the existence of other rows. Also, due to the Cartesian product, do not use this without limiting it to a small number of rows.
select to_char(d1.d, 'DD/MM/YYYY')
, to_char(d2.d, 'DD/MM/YYYY')
, decode(d1.n, 'MONDAY', '''Monday', 'FRIDAY', '''Friday')
from (select to_date('2011-02-28') + rownum as d
, to_char(to_date('2011-02-28') + rownum, 'FMDAY') as n
from user_objects where rownum <= 15) d1
, (select to_date('2011-02-28') + rownum as d
, to_char(to_date('2011-02-28') + rownum, 'FMDAY') as n
from user_objects where rownum <= 15) d2
where d1.d <= d2.d
and d2.d - d1.d < 7
and ((d1.d = d2.d and d1.n in ('MONDAY', 'FRIDAY'))
or (d1.n = 'TUESDAY' and d2.n = 'THURSDAY')
or (d1.n = 'SATURDAY' and d2.n = 'SUNDAY'))
order by d1.d, d2.d;
This is for SQL Server 2005+.
DECLARE #Date_From datetime, #Date_To datetime;
SET #Date_From = '20110301';
SET #Date_To = '20110315';
WITH datelist AS (
SELECT
Date = #Date_From,
GroupID = 1
UNION ALL
SELECT
Date = DATEADD(day, 1, Date),
GroupID = CASE
WHEN DATENAME(dw, Date) IN ('Sunday', 'Monday', 'Thursday', 'Friday')
THEN 1
ELSE 0
END + GroupID
FROM datelist
WHERE Date < #Date_To
)
SELECT
Date_From = MIN(Date),
Date_To = MAX(Date)
FROM datelist
GROUP BY GroupID
Output:
Date_From Date_To
----------------------- -----------------------
2011-03-01 00:00:00.000 2011-03-03 00:00:00.000
2011-03-04 00:00:00.000 2011-03-04 00:00:00.000
2011-03-05 00:00:00.000 2011-03-06 00:00:00.000
2011-03-07 00:00:00.000 2011-03-07 00:00:00.000
2011-03-08 00:00:00.000 2011-03-10 00:00:00.000
2011-03-11 00:00:00.000 2011-03-11 00:00:00.000
2011-03-12 00:00:00.000 2011-03-13 00:00:00.000
2011-03-14 00:00:00.000 2011-03-14 00:00:00.000
2011-03-15 00:00:00.000 2011-03-15 00:00:00.000