Is there any function to check for continuous date. I'm having problem on working with this issue below:
My table has a datetime
column with the following data:
----------
2015-03-11
2015-03-12
2015-03-13
2015-03-16
Given start date as 2015-3-11
and end date as 2015-3-17
. I want the result as:
----------
2015-03-11
2015-03-12
2015-03-13
Can anyone suggest anything ?
I'm thinking this is somewhat a variation of Grouping Islands of Contiguous Dates problem. This can be done using ROW_NUMBER()
:
SQL Fiddle
CREATE TABLE Test(
tDate DATETIME
)
INSERT INTO Test VALUES
('20150311'), ('20150312'), ('20150313'), ('20150316');
DECLARE @startDate DATE = '20150311'
DECLARE @endDate DATE = '20150317'
;WITH Cte AS(
SELECT
*,
RN = DATEADD(DD, - (ROW_NUMBER() OVER(ORDER BY tDATE) - 1), tDate)
FROM Test
WHERE
tDate >= @startDate
AND tDate < DATEADD(DAY, 1, @endDate)
)
SELECT CAST(tDate AS DATE)
FROM CTE
WHERE RN = @startDate
RESULT
|------------|
| 2015-03-11 |
| 2015-03-12 |
| 2015-03-13 |
Here is the SQL Server 2005 version:
SQL Fiddle
DECLARE @startDate DATETIME
DECLARE @endDate DATETIME
SET @startDate = '20150311'
SET @endDate = '20150317'
;WITH Cte AS(
SELECT
*,
RN = DATEADD(DD, -(ROW_NUMBER() OVER(ORDER BY tDATE)-1), tDate)
FROM Test
WHERE
tDate >= @startDate
AND tDate < DATEADD(DAY, 1, @endDate)
)
SELECT CONVERT(VARCHAR(10), tDate, 121)
FROM CTE
WHERE RN = @startDate
For MSSQL 2012
. This will return MAX continuous groups:
DECLARE @t TABLE(d DATE)
INSERT INTO @t VALUES
('20150311'),
('20150312'),
('20150313'),
('20150316')
;WITH
c1 AS(SELECT d, IIF(DATEDIFF(dd,LAG(d, 1, DATEADD(dd, -1, d)) OVER(ORDER BY d), d) = 1, 0, 1) AS n FROM @t),
c2 AS(SELECT d, SUM(n) OVER(ORDER BY d) AS n FROM c1)
SELECT TOP 1 WITH TIES MIN(d) AS StartDate, MAX(d) AS EndDate, COUNT(*) AS DayCount
FROM c2
GROUP BY n
ORDER BY DayCount desc
Output:
StartDate EndDate DayCount
2015-03-11 2015-03-13 3
For
('20150311'),
('20150312'),
('20150313'),
('20150316'),
('20150317'),
('20150318'),
('20150319'),
('20150320')
Output:
StartDate EndDate DayCount
2015-03-16 2015-03-20 5
Apply filtering in c1 CTE
:
c1 AS(SELECT d, IIF(DATEDIFF(dd,LAG(d, 1, DATEADD(dd, -1, d)) OVER(ORDER BY d), d) = 1, 0, 1) AS n FROM @t WHERE d BETWEEN '20150311' AND '20150320'),
For MSSQL 2008
:
;WITH
c1 AS(SELECT d, (SELECT MAX(d) FROM @t it WHERE it.d < ot.d) AS pd FROM @t ot),
c2 AS(SELECT d, CASE WHEN DATEDIFF(dd,ISNULL(pd, DATEADD(dd, -1, d)), d) = 1 THEN 0 ELSE 1 END AS n FROM c1),
c3 AS(SELECT d, (SELECT SUM(n) FROM c2 ci WHERE ci.d <= co.d) AS n FROM c2 co)
SELECT TOP 1 WITH TIES MIN(d) AS StartDate, MAX(d) AS EndDate, COUNT(*) AS DayCount
FROM c3
GROUP BY n
ORDER BY DayCount desc
you don't need to declare any start date or end date as other answers says, you need a row_num
with datediff
function:
create table DateFragTest (cDate date);
insert into DateFragTest
values ('2015-3-11'),
('2015-3-12'),
('2015-3-13'),
('2015-3-16')
with cte as
(select
cDate,
row_number() over (order by cDate ) as rn
from
DateFragTest)
select cDate
from cte t1
where datediff(day,
(select cDate from cte t2 where t2.rn=t1.rn+1),
t1.cDate)<>1
Output:
cDate
2015-03-11
2015-03-12
2015-03-13
SQLFIDDLE DEMO
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With