Tsql循环表之间的父子关系

时间:2012-12-11 15:31:50

标签: sql sql-server tsql recursive-descent

我有一张这样的表:

table item
(
   id    int,
   quantity float,
   father int, -- refer to item itself in case of subitem
)

我需要像这样总结数量和儿子的数量:

select i.id, max(i.quantity)+sum(ft.quantity) as quantity
from item i
left join item ft on ft.id=i.id
group by i.id

我的麻烦是因为父子之间的关系是递归的,所以我想总结他的祖父数量等...而且我不知道最大的深度,而不是我多次不能加入。

我该怎么办? 谢谢。

2 个答案:

答案 0 :(得分:2)

您必须使用递归CTE。这样的事情: SQL Fiddle Demo

这会给你类似的东西:

;WITH FathersSonsTree
AS
(
  SELECT Id, quantity, 0 AS Level
  FROM Items WHERE fatherid IS NULL
  UNION ALL
  SELECT c.id, c.quantity, p.level+1
  FROM FathersSonsTree p
  INNER JOIN items c ON c.fatherid = p.id
 ), ItemsWithMaxQuantities
AS
(
  SELECT *,
  ROW_NUMBER() OVER(PARTITION BY level 
                    ORDER BY quantity DESC) rownum
  FROM FathersSonsTree
  )
SELECT 
  ID,  
  (SELECT MAX(Quantity) 
   FROM FathersSonsTree t3 
   WHERE t3.level = t1.level
  ) + 
  ISNULL((SELECT SUM(t2.Quantity) 
   FROM FathersSonsTree t2
   WHERE t1.level - t2.level = 1), 0)
FROM FathersSonsTree t1
ORDER BY ID;

答案 1 :(得分:0)

您可以尝试构建一个递归CTE(公用表表达式),如本文关于SQLAuthority所述:

http://blog.sqlauthority.com/2012/04/24/sql-server-introduction-to-hierarchical-query-using-a-recursive-cte-a-primer/

作者Pinal Dave讨论了在employees表上使用递归CTE,该表具有自引用ManagerID的外键,以返回员工列表,其中包含他们与层次结构顶部之间的层数。员工没有经理(ManagerID = NULL)。这不完全是你想要的,但它可能会让你开始。

我做了一些实验,最后得到了与Mahmoud Gamal的解决方案非常相似的东西,但略有不同,不仅包括父母,祖父母,曾祖父母等数量,还包括儿童数量。

这是我使用的测试表:

CREATE TABLE Items(ID int IDENTITY
                      CONSTRAINT PK_Items PRIMARY KEY,
               Quantity int NOT NULL,
               ParentID int NULL
                            CONSTRAINT FK_Item_Parents REFERENCES Items(ID));

数据:

ID                  Quantity            ParentID            
------------------------------------------------------------
1                   10                  {NULL}
2                   10                  1
3                   10                  2
4                   10                  3
5                   10                  2

这是我的递归查询:

WITH cteRecursiveItems
AS (SELECT Id,
           quantity,
           0
          AS Level
    FROM Items
    WHERE ParentID IS NULL
    UNION ALL
    SELECT i.id,
           i.quantity,
           cri.level + 1
    FROM
         cteRecursiveItems cri
         INNER JOIN items i ON i.ParentID = cri.id)
SELECT ID,
       Quantity + (
                   SELECT MAX(Quantity)
                   FROM cteRecursiveItems cri3
                   WHERE cri3.level = cri1.level) + (
                                                 SELECT SUM(cri2.Quantity)
                                                 FROM cteRecursiveItems cri2
                                                 WHERE cri1.level - cri2.level = 1) as Total
FROM cteRecursiveItems cri1
ORDER BY ID;

这是我在测试表上运行它得到的结果:

ID                  Total             
----------------------------------------
1                   {NULL}
2                   30
3                   30
4                   40
5                   30

它仍然需要稍微调整一下,因为第一行和第二行都是10行。第1行应该总共有10行,第2行应该总共有20行。我正在做一个注释,试着解决这个问题。我回家(了。现在不能在我的雇主上花太多时间。 :)其他行具有我期望的值。