计算树中值的总和(递归查询)

时间:2016-09-11 11:16:39

标签: sql sql-server sql-server-2008 sql-server-2012

我在表employee(table,name,parentid)中有树结构,这个表可以嵌套.employees是与另一个表Sales(列,id,employeeid,quantity)的一对多关系。每位员工都有销售数量。我想计算每个员工与子员工一起的数量总和。我写了一些代码以便更清楚。

DECLARE @Employees TABLE(ID INT, Name NVARCHAR(100), ParentID INT);
DECLARE @Sales TABLE(ID INT, EmployeeID INT, Quantity INT);    

INSERT INTO @Employees(ID, Name, ParentID)VALUES
(1,N'Employee1', NULL),
(2,N'Employee2', 1),
(3,N'Employee3', 2),
(4,N'Employee4', NULL),
(5,N'Employee5', 4),
(6, N'Employee6', 5)

INSERT INTO @Sales(ID, EmployeeID, Quantity)VALUES
(1,1,4),
(2,1,2),
(3,2,3),
(4,3,2),
(5,3,7),
(6,5,8),
(7,5,3),
(8,6,2)

我加入了这个表,看起来像这样:

enter image description here

这是我的查询

;WITH cte 
AS
(
  SELECT e.ID, e.Name, e.ParentID FROM @Employees e
  WHERE e.ParentID IS NULL
  UNION ALL
  SELECT  e.ID, e.Name, e.ParentID  FROM @Employees e
    INNER JOIN cte c ON c.ID = e.ParentID
)
SELECT
     c.ID
    ,c.Name
    ,c.ParentID
    ,ISNULL(SUM(s.Quantity), 0) AS ParentSumSales
    ,ISNULL(LEAD(SUM(s.Quantity)) OVER(ORDER BY c.ID), 0) AS ChildSumSales
FROM cte c
    LEFT JOIN @Sales s ON s.EmployeeID = c.ID
GROUP BY c.ID, c.Name, c.ParentID

查询返回此结果:
enter image description here

但这不正确,我想得到这样的数据:

ID     Name        ParentSumSales    ChildSumSales
---    ---------   -------------     -------------
1      Employee1   6                 12
2      Employee2   3                 9   
3      Employee3   9                 0
4      Employee4   0                 13
5      Employee5   11                2
6      Employee6   2                 0

2 个答案:

答案 0 :(得分:1)

如果您的“员工”表偶尔会发生变化,我建议您实施Nested set model。写作会更复杂,但阅读会更简单,更快。

答案 1 :(得分:1)

您使用LEAD的尝试无效,因为它不会对所有以前的关卡进行求和,且ID必须是连续的。

首先为每位员工分析完整的层次结构,以便每个员工在每个层级中包含一次:

;WITH cte 
AS
(
  SELECT e.ID, e.Name, e.ID as sub_ID 
  FROM @Employees e
  -- no WHERE-condition to get all employees
  UNION ALL
  SELECT 
     c.ID, c.Name -- keep the initial employee
     ,e.ID as sub_ID
  FROM @Employees e
    INNER JOIN cte c ON c.sub_ID = e.ParentID
)

SELECT 
     c.ID
    ,c.Name
    -- parent level
    ,sum(case when c.id =  s.EmployeeID then s.Quantity else 0 end) AS ParentSumSales
    -- child level
    ,sum(case when c.id <> s.EmployeeID then s.Quantity else 0 end) AS ChildSumSales
FROM cte c
LEFT JOIN @Sales as s
ON s.EmployeeID = c.sub_ID
group by c.Name, c.id