2010-10-08 80 views
2

鉴于这两个表:递归SQL来查找关键路径?

[dbo].[Task] 
[Id] [Duration] [ScheduledStart] 
int int   Nullable DateTime 

[dbo].[TaskDependencies] 
[Id] [PredecessorTaskId] [TaskId] 
int FK_Task_Id   FK_Task_Id 

我试图找到任务紧前的最新结束日期。对于任务表,ScheduledStart可以为空。这背后的想法是,如果没有一个明确的计划的开始,也可能是从它的前辈(根级的任务必须有一个ScheduledStart,因此计算可以开始的地方)的。任务也可以有多个前任。

,我想出了一个假的递归功能(我认为)做什么我要找的。如果有,因为我已经习惯了更多的程序编程SQL写这更有效的方式是什么我不知道是。我应该让Function_A成为一个存储过程并让它自己调用吗?有没有这个可以用WITH语句来完成的方式(和是那些递归查询的更有效的方式,或者像这样的递归函数)?

DateTime Function_A(Task) 
{ 
    var predecessorList = getPredecessors(Task) 
    var latestEndDate; 
    var currentPredecessorLatestEndDate; 

    ForEach(Predecessor in predecessorList) 
    { 
     if(Predecessor.ScheduledStart != null) 
     { 
      if(latestEndDate != null) 
      { 
       if(Predecessor.StartDate + Predecessor.Duration > latestEndDate) 
       { 
        latestEndDate = Predecessor.StartDate + Predecessor.Duration; 
       } 
      } 
      else 
      { 
       latestEndDate = Predecessor.StartDate + Predecessor.Duration; 
      } 

     } 
     else 
     { 
      currentPredecessorLatestEndDate = Function_A(Predecessor.Id); 

      if(latestEndDate != null) 
      { 
       if(currentPredecessorEndDate > latestEndDate) 
       { 
        latestEndDate = currentPredecessorEndDate; 
       } 
      } 
      else 
      { 
       latestEndDate = currentPredecessorEndDate;    
      } 
     } 
    } 

    return latestEndDate; 
} 

感谢您的帮助!

回答

1

您可以使用递归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.

+0

感谢,肯定把我在正确的方向。 – Ocelot20 2010-10-08 15:21:17