2010-10-08 129 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