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:
Could you let me know how to get this result please?
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