Этот работает с оракулом, и, начиная с этого, это должно быть возможно и в SQL Server. (включая тестовый скрипт)
create table schedule (id number, employee_id number, project_id number, day_id number);
insert into schedule (id, employee_id, project_id, day_id)
values(1,64,2,168);
insert into schedule (id, employee_id, project_id, day_id)
values(2,64,2,169);
insert into schedule (id, employee_id, project_id, day_id)
values(3,64,2,170);
insert into schedule (id, employee_id, project_id, day_id)
values(4,64,2,171);
insert into schedule (id, employee_id, project_id, day_id)
values(5,64,1,169);
insert into schedule (id, employee_id, project_id, day_id)
values(6,64,1,170);
insert into schedule (id, employee_id, project_id, day_id)
values(7,64,1,171);
insert into schedule (id, employee_id, project_id, day_id)
values(8,64,1,172);
insert into schedule (id, employee_id, project_id, day_id)
values(9,64,2,182);
insert into schedule (id, employee_id, project_id, day_id)
values(10,64,2,183);
insert into schedule (id, employee_id, project_id, day_id)
values(11,64,2,184);
insert into schedule (id, employee_id, project_id, day_id)
values(11,65,3,184);
select *
FROM (
select
employee_id,
project_id,
first_day,
nvl(last_day,
lead(last_day) over (
partition by employee_id, project_id
order by nvl(first_day, last_day)
)
) last_day
from (
select -- this identifies start and end rows of an interval
employee_id,
project_id,
decode (day_id - prev_day, 1, null, day_id) first_day, -- uses day_id, if prev_day is not really the previous day, i.e. a gap or null
decode (day_id - next_day, -1, null, day_id) last_day
from (
select -- this select adds columns for the previous and next day, in order to identify the boundaries of intervals
employee_id,
project_id,
day_id,
lead(day_id) over (
partition by employee_id, project_id
order by day_id
) next_day,
lag(day_id) over (
partition by employee_id, project_id
order by day_id
) prev_day
from schedule
)
)
where first_day is not null
or last_day is not null-- just filter the rows, that represent start or end dates
)
where first_day is not null
производит этот вывод:
64 1 169 172
64 2 168 171
64 2 182 184
65 3 184 184