I have tried the following in LINQPad:
create table users
(
    id int not null,
    startdate datetime not null,
    enddate datetime not null
)
go
insert into users(id, startdate, enddate) values(1, '01/01/2000', '01/02/2000')
insert into users(id, startdate, enddate) values(1, '01/03/2000', '01/04/2000')
insert into users(id, startdate, enddate) values(2, '01/01/2000', '01/02/2000')
insert into users(id, startdate, enddate) values(2, '01/03/2000', '01/04/2000')
insert into users(id, startdate, enddate) values(2, '01/05/2000', '01/06/2000')
insert into users(id, startdate, enddate) values(3, '01/01/2000', '01/02/2000')
insert into users(id, startdate, enddate) values(3, '01/03/2000', '01/04/2000')
insert into users(id, startdate, enddate) values(3, '01/06/2000', '01/07/2000')
insert into users(id, startdate, enddate) values(4, '01/01/2000', '01/02/2000')
go
select * from users 
go
// This query gave the result seen in the image
select id, startdate, enddate, rownum = dense_rank() over(partition by id order by enddate) from users
I want to write a query which will return only the IDs 1 and 2 (not 3 and 4) because:
- ID 1 – has more than 1 rows and startdate of its rownum 2 is 1 day ahead of enddate of its rownum 1
 - ID 2 – has more than 1 rows and startdate of its rownum n + 1 is 1 day ahead of enddate of its rownum n
 - ID 3 – THOUGH has more than 1 rows, startdate of its rownum 3 is NOT 1 day ahead (but 2 days) of enddate of its rownum 2. Hence, it is not qualified
 - ID 4 – DOES NOT HAVE more than 1 rows. Hence, it is not qualified
 
Could you let me know how to get this result please?
Advertisement
Answer
You could use window function lag() to recover the previous enddate, then aggregation and filter in the having clause:
select id
from (
    select 
        t.*,
        lag(enddate) over(partition by id order by enddate) lag_enddate
    from users t
) t
group by id 
having 
    count(*) > 1
    and max(case 
        when lag_enddate is null or startdate = dateadd(day, 1, lag_enddate) 
        then 0 else 1 
    end) = 0
| id | | -: | | 1 | | 2 |
In archaic versions of SQL Server, that do not support window functions, you can emulate lag() with a correlated subquery:
select id
from (
    select 
        t.*,
        (select max(enddate) from users t1 where t1.id = t.id and t1.enddate < t.enddate) lag_enddate
    from users t
) t
group by id 
having 
    count(*) > 1
    and max(case when lag_enddate is null or startdate = dateadd(day, 1, lag_enddate) then 0 else 1 end) = 0
