Вы можете использовать рекурсивный CTE, чтобы найти все последующие задачи. Затем вы можете рассчитать первую доступную дату начала на основе последней конечной дочерней задачи. Потребуется несколько проходов, если у задачи есть дочерние задачи, у которых неизвестная дата начала.
Пример кода с использованием рекурсивного CTE:
;with Predecessors as
(
select Id as RootId
, null as ChildId
from @Task
union all
select p.RootId
, cd.PredecessorTaskId as ChildId
from @TaskDependencies cd
join Predecessors p
on cd.TaskId = ISNULL(p.ChildId, p.RootId)
)
select RootId
, max(dateadd(day, c.Duration+1, c.ScheduledStart))
from Predecessors p
join @Task c
on p.ChildId = c.Id
-- Filter out tasks with child tasks that themselves have
-- an unknown start date.
where not exists
(
select *
from Predecessors p2
join @Task c2
on p2.ChildId = c2.Id
where p2.RootId = p.RootId
and c2.ScheduledStart is null
)
group by
RootId
Данные испытаний:
declare @Task table (Id int, Duration int, ScheduledStart datetime)
insert @Task
select 1, 3, '2010-01-01'
union all select 2, 3, '2010-01-03'
union all select 3, 3, null
union all select 4, 3, '2010-01-01'
union all select 5, 3, null
declare @TaskDependencies table (PredecessorTaskId int, TaskId int)
insert @TaskDependencies
select 1, 3
union all select 2, 3
union all select 4, 5
union all select 3, 5
Это печатает:
3 2010-01-07
Отфильтровывает задачу 5, в которой есть дочерние задачи с неизвестной датой начала. Если вы введете рассчитанную дату начала для задачи 3, вы сможете рассчитать дату начала для задачи 5.