SQL中树结构元素的总和

时间:2014-12-30 00:50:02

标签: sql recursion sum

我有两张表,其定义如下:

CREATE TABLE Parts (
   id INTEGER PRIMARY KEY, 
   Name TEXT, 
   Quantity INTEGER, 
   Parentid INTEGER
);  

CREATE TABLE Weight(
   Name TEXT, 
   Weight INTEGER
);

“零件”表包含父零件和子零件的行。 对于产品A,有几个部分(B1和B2)和子部分(C1-C4):
内容如下:
A:2xB1,2xB2,1xC1,5xC2
B1:3xC1,2xC2
B2:1xB1,1xC3

和重量之类的东西:
C1:5
C2:4
C3:2

...或:

╔════════════════════════════════════╗
║ Parts                              ║
╠═══════╦══════╦══════════╦══════════╣
║ id    ║ Name ║ Quantity ║ Parentid ║
╠═══════╬══════╬══════════╬══════════╣
║ A     ║ A    ║ 1        ║ NULL     ║
║ B1    ║ B1   ║ 2        ║ A        ║
║ B2    ║ B2   ║ 2        ║ A        ║
║ C1    ║ C1   ║ 1        ║ A        ║
║ C2    ║ C2   ║ 5        ║ A        ║
║ C1    ║ C1   ║ 3        ║ B1       ║
║ C2    ║ C2   ║ 2        ║ B1       ║
║ B1    ║ B1   ║ 1        ║ B2       ║
║ C3    ║ C3   ║ 1        ║ B2       ║
╚═══════╩══════╩══════════╩══════════╝

╔═════════════════╗
║ Weight          ║
╠════════╦════════╣
║ Name   ║ Weight ║
╠════════╬════════╣
║ C1     ║ 5      ║
║ C2     ║ 4      ║
║ C3     ║ 2      ║
║ C4     ║ 8      ║
╚════════╩════════╝

表中是子部件C1-C4的重量和每个部件的数量。 如何获得每个部件和整个产品的重量?

我知道它是递归CTE的东西,但我无法得到我想要的结果。 我在Recursive sum in tree structure的帮助下尝试了它但没有取得多大成功。

这就是我所拥有的:

WITH c as (
SELECT Parts.id, 
  Parts.quantity, 
  Parts.id as RootID, 
  (Parts.quantity * Weight.weight) as Weight 
FROM Parts LEFT JOIN Weight ON Weight.name = Parts.name
UNION ALL
SELECT Parts.id, 
  Parts.quantity, 
  c.RootID, 
  (Parts.quantity * Weight.weight) as Weight
FROM Parts LEFT JOIN Weight on Weight.name = Parts.name
  INNER JOIN c on Parts.Parentid = c.id
)
SELECT Parts.id, 
  Parts.parent, 
  Parts.name, 
  Parts.quantity, 
  S.SumWeight
FROM Parts INNER JOIN (
  SELECT rootid, 
    SUM(weight) as SumWeight
  FROM c 
  GROUP BY rootid
) as S on Parts.id = S.rootid 
ORDER BY Parts.id

我想要达到的结果是:
    A 121
    B1 23
    B2 25

感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

关于如何在设计中总结重量以避免重复包含重量,我们并不清楚,但这是使用与您建议的表格非常类似的表格进行递归的示例。

CREATE TABLE Parts (
   Id varchar(20), 
   Name varchar(20), 
   Quantity INTEGER, 
   ParentId varchar(20)
);  

CREATE TABLE Weight(
   Name varchar(20), 
   [Weight] INTEGER
);

insert into Parts (Id, Name, Quantity, Parentid)
values ('A','A', 1, NULL),
('B1','B1', 2, 'A'),
('B2','B2', 2, 'A'),
('C1','C1', 1, 'A'),
('C2','C2', 5, 'A'),
('C1','C1', 3, 'B1'),
('C2','C2', 2, 'B1'),
('B1','B1', 1, 'B2'),
('C3','C3', 1, 'B2');

insert into Weight(Name, Weight)
values ('C1', 5),
('C2', 4),
('C3', 2),
('C4', 8);


WITH a as (
  SELECT x.Id as EndId,
    x.Id as ComponentId,
    0 as ComponentQuantity,
    1 as Lvl
  FROM Parts x INNER JOIN Parts y ON x.Id = y.ParentId -- must have at least 1 child...
  GROUP BY x.Id
  UNION ALL
  SELECT a.EndId,
    x.Id as ComponentId,
    x.Quantity as ComponentQuantity,
    a.Lvl + 1 as Lvl
  FROM Parts x INNER JOIN a ON x.ParentId = a.ComponentId
)
SELECT a.EndId,
  SUM(a.ComponentQuantity) as SumQuantity,
  SUM(a.ComponentQuantity * b.Weight) as SumWeight
FROM a INNER JOIN Weight b ON a.ComponentId = b.Name
WHERE a.EndId <> a.ComponentId
    AND a.Lvl = 2 -- treat 1st child as the weighted subassembly of interest
GROUP BY a.EndId;