想通如何做到這一點。該方法有點複雜,也許別人可以想出一個整潔的版本。
該方法包括四個步驟:
在對給定項目的所有任務運行ROW_NUMBER功能。通過ParentId分區,以便給定父項的所有子任務都編號爲1,2,3,4等。這適用於任務層次結構的所有級別;
使用遞歸CTE(公用表表達式)從葉級到頂級遍歷任務層次結構。這將根據TimeCode表中的父子關係構建任務層次結構。最初我嘗試在這裏包含ROW_NUMBER函數,但由於微軟實施CTE的方式,這不起作用;
將HIERARCHYID列添加到在步驟2中構建的結構中;
對記錄集執行自連接以獲取結構中每個節點的所有子節點。按父節點分組並計算每個子節點記錄的時間。請注意,HIERARCHYID方法IsDescendantOf不僅返回節點的子節點,還返回節點本身。因此,如果任何時間都記錄在父任務以及子任務上,它將包含在該父節點的總時間中。
這裏的腳本:
-- Cannot include a ROW_NUMBER function within the recursive member of the
-- common table expression as SQL Server recurses depth first. ie SQL
-- Server recurses each row separately, completing the recursion for a
-- given row before starting the next.
-- To get around this, use ROW_NUMBER outside the common table expression.
DECLARE @tblTask TABLE (TimeCodeId INT, ParentId INT, ProjectID INT,
Level INT, TaskIndex VARCHAR(12), Duration FLOAT);
INSERT INTO @tblTask (TimeCodeId, ParentId, ProjectID,
Level, TaskIndex, Duration)
SELECT tc.TimeCodeId,
tc.ParentId,
CASE
WHEN tc.ParentId IS NULL THEN tc.ReferenceId1
ELSE tc.ReferenceId2
END AS ProjectID,
1 AS Level,
CAST(ROW_NUMBER() OVER (PARTITION BY tc.ParentId
ORDER BY tc.[Description]) AS VARCHAR(12))
AS TaskIndex,
ts.Duration
FROM Time.TimeCode tc
LEFT JOIN
( -- Get time sub-totals for each task.
SELECT TimeCodeId,
SUM(Duration) AS Duration
FROM Time.Timesheet
WHERE ReferenceId2 IN (12196, 12198)
GROUP BY TimeCodeId
) ts
ON tc.TimeCodeId = ts.TimeCodeId
WHERE ReferenceId2 IN (12196, 12198)
ORDER BY [Description];
DECLARE @tblHierarchy TABLE (HierarchyNode HIERARCHYID,
Level INT, Duration FLOAT);
-- Common table expression that builds up the task hierarchy recursively.
WITH cte_task_hierarchy AS
(
-- Anchor member.
SELECT t.TimeCodeId,
t.ParentID,
t.ProjectID,
t.Level,
CAST('/' + t.TaskIndex + '/' AS VARCHAR(200)) AS HierarchyNodeText,
t.Duration
FROM @tblTask t
UNION ALL
-- Dummy root node for HIERARCHYID.
-- (easier to add it after another query so don't have to cast the
-- NULLs to data types)
SELECT NULL AS TimeCodeId,
NULL AS ParentID,
NULL AS ProjectID,
0 AS Level,
CAST('/' AS VARCHAR(200)) AS HierarchyNodeText,
NULL AS Duration
UNION ALL
-- Recursive member that walks up the task hierarchy.
SELECT tp.TimeCodeId,
tp.ParentID,
th.ProjectID,
th.Level + 1 AS Level,
CAST('/' + tp.TaskIndex + th.HierarchyNodeText AS VARCHAR(200))
AS HierarchyNodeText,
th.Duration
FROM cte_task_hierarchy th
JOIN @tblTask tp ON th.ParentID = tp.TimeCodeId
)
INSERT INTO @tblHierarchy (HierarchyNode,
Level, Duration)
SELECT hierarchyid::Parse(cth.HierarchyNodeText),
cth.Level, cth.Duration
FROM cte_task_hierarchy cth
-- This filters recordset to exclude intermediate steps in the recursion
-- - only want the final result.
WHERE cth.ParentId IS NULL
ORDER BY cth.HierarchyNodeText;
-- Show the task hierarchy.
SELECT *, HierarchyNode.ToString() AS NodeText
FROM @tblHierarchy;
-- Calculate the sub-totals for each task in the hierarchy.
SELECT t1.HierarchyNode.ToString() AS NodeText,
COALESCE(SUM(t2.Duration), 0) AS DurationTotal
FROM @tblHierarchy t1
JOIN @tblHierarchy t2
ON t2.HierarchyNode.IsDescendantOf(t1.HierarchyNode) = 1
GROUP BY t1.HierarchyNode;
結果:
第一個記錄(與HIERARCHYID列任務結構):
HierarchyNode Level Duration NodeText
------------- ----- -------- --------
0x 0 NULL /
0x58 1 NULL /1/
0x5AC0 2 12.15 /1/1/
0x5AD6 3 8.92 /1/1/1/
0x5ADA 3 11.08 /1/1/2/
0x5ADE 3 7 /1/1/3/
0x5B40 2 182.18 /1/2/
0x5B56 3 233.71 /1/2/1/
0x5B5A 3 227.27 /1/2/2/
0x5BC0 2 45.4 /1/3/
0x68 1 NULL /2/
0x6AC0 2 8.5 /2/1/
0x6B40 2 2.17 /2/2/
0x6BC0 2 8.91 /2/3/
0x6C20 2 1.75 /2/4/
0x6C60 2 60.25 /2/5/
第二個記錄(具有子任務 - 每個任務的總計):
NodeText DurationTotal
-------- -------------
/ 809.29
/1/ 727.71
/1/1/ 39.15
/1/1/1/ 8.92
/1/1/2/ 11.08
/1/1/3/ 7
/1/2/ 643.16
/1/2/1/ 233.71
/1/2/2/ 227.27
/1/3/ 45.4
/2/ 81.58
/2/1/ 8.5
/2/2/ 2.17
/2/3/ 8.91
/2/4/ 1.75
/2/5/ 60.25
如果您可以向我們展示您正在使用的模式可能會幫助我們想出一種適合您的方法。 – mwigdahl 2012-01-17 21:56:52
兩個表格,Time.TimeCode存儲項目任務的結構,Time.TimeSheet存儲每個任務記錄的時間。 – 2012-01-17 21:59:08
這兩個表的更多細節:(1)Time.TimeCode包含列TimeCodeId,任務的ID; ParentId,任務父項的ID; Description和ReferenceId2,項目ID。給定項目的所有任務都具有相同的ReferenceId2。 (2)Time.Timesheet包含TimesheetId,時間條目的ID; TimeCodeId,TimeCode表的外鍵;日期,工作完成日期(日期數據類型);和Duration(持續時間),這是在任務上花費的時間(float)。 「... Id」列都是整數。 – 2012-01-17 22:16:11