Sql 如何从Postgres中的嵌套估计中找到材料需求

Sql 如何从Postgres中的嵌套估计中找到材料需求,sql,postgresql,product,postgresql-9.2,capacity-planning,Sql,Postgresql,Product,Postgresql 9.2,Capacity Planning,产品评估包含子产品。 子产品还可以包含子产品等。 最后,树木的叶子覆盖了材料。 最大嵌套级别为10 订单还包含产品、子产品和订购数量的材料。 如何找到满足订单所需的材料需求 产品、子产品和材料在单个表格中: create table toode (productid char(10) primary key ); 估算表: create table dok ( dokumnr serial primary key, productid char(10) not null referen

产品评估包含子产品。 子产品还可以包含子产品等。 最后,树木的叶子覆盖了材料。 最大嵌套级别为10

订单还包含产品、子产品和订购数量的材料。 如何找到满足订单所需的材料需求

产品、子产品和材料在单个表格中:

create table toode (productid char(10) primary key );
估算表:

create table dok (
  dokumnr serial primary key,
  productid char(10) not null references toode
);
估算中的子产品和材料:

create table rid (
  id serial primary key,
  dokumnr int not null references dok,
  itemid char(10) not null references toode,
  quantity  numeric(12,4) -- quantity required to make one product
);
订单:

create table orderrows (
  id serial primary key,
  itemid char(10) not null references toode,
  quantity  numeric(12,4)  -- ordered quantity
);
结果应为返回物料和子产品需求的查询:

itemid char(10) not null references toode,
requiredquantity  numeric(12,4) -- total quantity of items required to make ordered products
如何在Postgresql 9.2中实现这一点? 描述的字段应保留在这些表中。可以添加额外的 列和表,如果这有帮助的话。 是否有可能进行一些通用的查询,该查询使用无限制的嵌套级别。 或者,这是创建查询的最佳方法,该查询会将某些部分重复10次以获得最高的查询级别

更新

估计数

product1
  material1  2 pcs
  subproduct2  3 pcs


subproduct2
  material2 4 pcs
被描述为

insert into dok values (1,'product1');
  insert into rid (dokumnr, itemid, quantity) values (1, 'material1', 2);
  insert into rid (dokumnr, itemid, quantity) values (1, 'subproduct2', 3);

insert into dok values (2,'subproduct2');
  insert into rid (dokumnr, itemid, quantity) values (2, 'material2', 4);
如果订购了10件产品1,则描述如下:

insert into orderrows (itemid, quantity ) values ('product1', 10);
结果应该是:

material1  20 
material2  120
材料1数量按10*2计算

材料2数量按10*3*4计算

更新2

当最后一级包含多行时,Joachim answer给出的多级估计结果不正确。最后一次连接
rid2上的左连接rid2.dokumnr=dok2.dokumnr
返回多行,结果表重复

测试用例:

预期:

每个数量为1,因此每个物料的结果数量必须为1

观察到:

Material2和Material3行是重复的

如何解决这个问题?查询应该确定叶节点本身。叶节点在数据中没有特别标记。

请尝试以下查询:

;with recursive cte as (
    select r.itemid, r.quantity * o.quantity as quantity, false as is_material
    from orderrows as o
        inner join dok as d on d.productid = o.itemid
        inner join rid as r on r.dokumnr = d.dokumnr

    union

    select r.itemid, r.quantity * o.quantity as quantity, itemid like 'material%'
    from cte as o
        inner join dok as d on d.productid = o.itemid
        inner join rid as r on r.dokumnr = d.dokumnr
)
select * from cte as c
where c.itemid not in (select t.productid from dok as t);
下面是测试它的示例。这里我假设您将materials定义为名称以“material”开头的产品,但我认为您应该在DB中有一个属性
is_material
或类似的东西,因此您可以更改此条件


更新-测试用例

这应该使用递归查询来完成

WITH RECURSIVE t(itemid,qty) AS (
  SELECT itemid,quantity,false isleaf FROM orderrows
  UNION ALL
  SELECT rid.itemid,(rid.quantity*t.qty)::NUMERIC(12,4),
         dok2.productid IS NULL
  FROM t 
  JOIN dok ON dok.productid=t.itemid
  JOIN rid ON rid.dokumnr=dok.dokumnr
  LEFT JOIN dok dok2 ON dok2.productid=rid.itemid
)
SELECT itemid, SUM(qty) FROM t WHERE isleaf GROUP BY itemid

.

您能把一些测试数据和期望的输出放在一起吗?@Roman Pekar:我用样本数据和结果更新了问题,就像您想看的“带递归”一样(请看这里:)。我目前无法访问postgres系统来实际构建/测试示例查询。@SpaceDog:谢谢。我会尽量理解递归,从来没有用过它。这可以通过将估算表与orderrows连接10次,并在不确定这是最佳方式、嵌套级别是硬编码的且查询很长时使用大量合并和CASE来实现。您可以使用SQLFiddle创建查询。+1是的,测试它是否为leaf比假设名称为“material”要好,但我认为OP应该有更有效的方法谢谢。杰出的如何将列添加到结果表中,该表包含使用此行材料的产品的逗号分隔列表。有没有可能使用string_add或一些数组函数来完成这个任务?@Andrus检查一下,看看这是不是你要找的东西。@Joachim。非常感谢。这很有效。然而,您的答案是不正确的,它会产生错误的结果,行是重复的。我更新了问题和未标记的答案。如何解决这个问题?@Andrus更新了答案,材料的sqlfiddle.itemids可以是任何代码。它们不是从材料开始的。查询应该确定叶节点本身,数据不具有这样的属性。约阿希姆叶节的测定是错误的。我更新了queston并提供了testcase。如何解决这个问题?谢谢。这可能行得通,几天前我把它投了更高的票。然而,我将Joahchim的答案标记为答案,因为他首先提供了一般解决方案,这也允许获得我在回答评论中询问的材料列表,Joachim毫无疑问提供了解决方案,Joahchim确实首先提供了一般解决方案,感谢投票
WITH RECURSIVE t(itemid,qty) AS (
  SELECT itemid,quantity,false isleaf FROM orderrows
  UNION ALL
  SELECT rid.itemid,(rid.quantity*t.qty)::NUMERIC(12,4),
         dok2.productid IS NULL
  FROM t 
  JOIN dok ON dok.productid=t.itemid
  JOIN rid ON rid.dokumnr=dok.dokumnr
  LEFT JOIN dok dok2 ON dok2.productid=rid.itemid
)
SELECT itemid, SUM(qty) FROM t WHERE isleaf GROUP BY itemid