【问题标题】:Calculate sum of values in tree(recursive query)计算树中值的总和(递归查询)
【发布时间】:2017-01-19 00:24:18
【问题描述】:

我在员工表(id、name、parentid)中有树结构,这个表可以嵌套。employees 与另一个表 Sales 是一对多的关系,其中包含列(id、employeeid、数量)。每个员工都有销售数量。我想计算每个员工以及儿童员工的数量总和。为了更清楚,我写了一些代码。

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)

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

这是我的查询

;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

查询返回这个结果:

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

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

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      您使用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
      

      【讨论】:

      • 是的,它可以工作,谢谢,但是在左连接内部不需要使用 group by 和 sum,没有它也可以工作
      • @www1986:这是尝试修复原始查询的遗留问题,之后我没有检查它:) 我会相应地修改我的答案
      猜你喜欢
      • 2021-11-01
      • 2021-10-02
      • 2013-11-26
      • 2011-02-15
      • 2020-05-25
      • 1970-01-01
      • 1970-01-01
      • 2018-07-16
      • 2012-01-26
      相关资源
      最近更新 更多