Sql 如何从Postgres中的嵌套估计中找到材料需求
产品评估包含子产品。 子产品还可以包含子产品等。 最后,树木的叶子覆盖了材料。 最大嵌套级别为10 订单还包含产品、子产品和订购数量的材料。 如何找到满足订单所需的材料需求 产品、子产品和材料在单个表格中: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
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