【问题标题】:Sum of elements for tree structure in SQLSQL中树结构的元素总和
【发布时间】:2015-02-26 04:31:00
【问题描述】:

我有两个表,定义如下:

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):
内容类似于:
答: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

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

感谢任何帮助!

【问题讨论】:

  • 23 等于 B1 或 121 等于 A?数量?你怎么想出来的?
  • 如果要加入名称列,请考虑使用 varchar 而不是文本。更好的是,如果可能的话,考虑加入整数以提高性能。
  • B1 = 3xC1 (=3*5) + 2xC2 (=2*4) = 15+8 = 23,重量乘以数量。是的。性能对我来说不是问题,我只是个初学者。
  • 您使用的是哪个 DBMS? Postgres?

标签: sql recursion sum


【解决方案1】:

尚不清楚在您的设计中应如何对权重求和以避免重复包含权重,但这是使用与您建议的表格非常相似的表格进行递归的示例。

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;

【讨论】:

  • 问题是它不包括A(B1和B2)和B2(B1)的“孩子”的重量。它仅添加 C1-C4 的值,但 B1(对于 B2)和 A 的相应 B2/B1 也具有权重。 B2 必须称重 B1+C3。
  • 我不同意;它包括 B1 的重量,根据定义,它应该包括所有组件的重量(B2 等)。无论如何,使用最后一个 where 子句来改变行为。你的逻辑不是问题。这是递归。
  • 是的,但是 B1 包含在 B2 中,但是此查询返回 B2:2 和 B1:23。但它应该返回:B1:23 和 B2:25
  • B1 在权重表中没有提供的值;如果这对您很重要,请将权重表的连接设为左连接。
  • 但我可以使用 SELECT parentid, SUM(quantity*weight) FROM parts LEFT JOIN weight ON weight.name = parts.name GROUP BY parentid 来获得相同的结果(我错了)。 B1 具有权重,因为 B1 由 C1 和 C2 组成。 B1 是 B2 的一部分,因此 B2 的重量必须大于 B1。这就是为什么我想通过递归来计算 B1 和 B2(=> 权重)所需的值,最后仅根据 C1-C4 的已知权重计算 A。
猜你喜欢
  • 2019-06-28
  • 1970-01-01
  • 2021-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多