如何编写SQL查询来计算与其父装配一起出售的零部件数量?(Postgres 11/递归CTE?) [英] How can I write a SQL query to calculate the quantity of components sold with their parent assemblies? (Postgres 11/recursive CTE?)
问题描述
我的目标
计算作为其父装配的一部分出售的零件的总和.
To calculate the sum of components sold as part of their parent assemblies.
我确定这肯定是一个常见的用例,但是我还没有找到能导致我寻找结果的文档.
I'm sure this must be a common use case, but I haven't yet found documentation that leads to the result I'm looking for.
背景
我在CentOS 7上运行Postgres 11.我有一些如下表:
I'm running Postgres 11 on CentOS 7. I have some tables like as follows:
CREATE TABLE the_schema.names_categories (
id INTEGER NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
created_at TIMESTAMPTZ DEFAULT now(),
thing_name TEXT NOT NULL,
thing_category TEXT NOT NULL
);
CREATE TABLE the_schema.relator (
id INTEGER NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
created_at TIMESTAMPTZ DEFAULT now(),
parent_name TEXT NOT NULL,
child_name TEXT NOT NULL,
child_quantity INTEGER NOT NULL
);
CREATE TABLE the_schema.sales (
id INTEGER NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
created_at TIMESTAMPTZ DEFAULT now(),
sold_name TEXT NOT NULL,
sold_quantity INTEGER NOT NULL
);
这样的视图,主要是将类别键与relator.child_name关联以进行过滤:
And a view like so, which is mainly to associate the category key with relator.child_name for filtering:
CREATE VIEW the_schema.relationships_with_child_catetgory AS (
SELECT
r.parent_name,
r.child_name,
r.child_quantity,
n.thing_category AS child_category
FROM
the_schema.relator r
INNER JOIN
the_schema.names_categories n
ON r.child_name = n.thing_name
);
这些表包含一些这样的数据:
And these tables contain some data like this:
INSERT INTO the_schema.names_categories (thing_name, thing_category)
VALUES ('parent1', 'bundle'), ('child1', 'assembly'), ('subChild1', 'component'), ('subChild2', 'component');
INSERT INTO the_schema.relator (parent_name, child_name, child_quantity)
VALUES ('parent1', 'child1', 1),('child1', 'subChild1', 10), ('child1', 'subChild2', 2);
INSERT INTO the_schema.sales (sold_name, sold_quantity)
VALUES ('parent1', 1), ('parent1', 2);
我需要构造一个查询,给定这些数据,该查询将返回如下内容:
I need to construct a query that, given these data, will return something like the following:
child_name | sum_sold
------------+----------
subChild1 | 30
subChild2 | 6
(2 rows)
问题是我还不知道如何解决这个问题,实际上,当我键入内容时,它变得越来越吓人.我很难想象需要建立的连接,因此很难以合乎逻辑的方式开始.通常,Molinaro的 SQL Cookbook 有一些入门知识,并且确实有关于分层查询的部分,但是据我所知,它们都不满足特定的目的.
The problem is that I haven't the first idea how to go about this and in fact it's getting scarier as I type. I'm having a really hard time visualizing the connections that need to be made, so it's difficult to get started in a logical way. Usually, Molinaro's SQL Cookbook has something to get started on, and it does have a section on hierarchical queries, but near as I can tell, none of them serve this particular purpose.
根据我对该站点的研究,似乎我可能需要使用递归CTE/公用表表达式,如
Based on my research on this site, it seems like I probably need to use a recursive CTE /Common Table Expression, as demonstrated in this question/answer, but I'm having considerable difficulty understanding this method and how to use this it for my case.
从上面链接的E. Brandstetter的答案中查看示例,我得出:
Aping the example from E. Brandstetter's answer linked above, I arrive at:
WITH RECURSIVE cte AS (
SELECT
s.sold_name,
r.child_name,
s.sold_quantity AS total
FROM
the_schema.sales s
INNER JOIN
the_schema.relationships_with_child_catetgory r
ON s.sold_name = r.parent_name
UNION ALL
SELECT
c.sold_name,
r.child_name,
(c.total * r.child_quantity)
FROM
cte c
INNER JOIN
the_schema.relationships_with_child_catetgory r
ON r.parent_name = c.child_name
) SELECT * FROM cte
其中的一部分:
sold_name | child_name | total
-----------+------------+-------
parent1 | child1 | 1
parent1 | child1 | 2
parent1 | subChild1 | 10
parent1 | subChild1 | 20
parent1 | subChild2 | 2
parent1 | subChild2 | 4
(6 rows)
但是,这些结果包括不需要的行(前两行),当我尝试通过在两个部分中添加 where r.child_category ='component'
来过滤CTE时,查询不返回任何行:
However, these results include undesired rows (the first two), and when I try to filter the CTE by adding where r.child_category = 'component'
to both parts, the query returns no rows:
sold_name | child_name | total
-----------+------------+-------
(0 rows)
,当我尝试分组/汇总时,出现以下错误:错误:递归查询的递归术语
and when I try to group/aggregate, it gives the following error:
ERROR: aggregate functions are not allowed in a recursive query's recursive term
我坚持如何过滤掉不需要的行并进行聚合;显然,我无法理解此递归CTE的工作原理.感谢所有指导!
I'm stuck on how to get the undesired rows filtered out and the aggregation happening; clearly I'm failing to comprehend how this recursive CTE works. All guidance is appreciated!
推荐答案
基本上,您已经找到了解决方案.如果也将数量和类别存储在CTE中,则可以在其后简单地添加 WHERE
过滤器和 SUM
聚合:
Basically you have the solution. If you stored the quantities and categories in your CTE as well, you can simply add a WHERE
filter and a SUM
aggregation afterwards:
SELECT
child_name,
SUM(sold_quantity * child_quantity)
FROM cte
WHERE category = 'component'
GROUP BY child_name
我的整个查询是这样的(仅在上面提到的详细信息与您的详细信息有所不同):
My entire query looks like this (which only differs in the details I mentioned above from yours):
WITH RECURSIVE cte AS (
SELECT
s.sold_name,
s.sold_quantity,
r.child_name,
r.child_quantity,
nc.thing_category as category
FROM
sales s
JOIN relator r
ON s.sold_name = r.parent_name
JOIN names_categories nc
ON r.child_name = nc.thing_name
UNION ALL
SELECT
cte.sold_name,
cte.sold_quantity,
r.child_name,
r.child_quantity,
nc.thing_category
FROM cte
JOIN relator r ON cte.child_name = r.parent_name
JOIN names_categories nc
ON r.child_name = nc.thing_name
)
SELECT
child_name,
SUM(sold_quantity * child_quantity)
FROM cte
WHERE category = 'component'
GROUP BY child_name
注意:我没有使用您的视图,因为我发现直接从表中获取数据而不是联接已有的数据更加方便.但这只是我个人喜欢的方式:)
Note: I didn't use your view, because I found it more handy to fetch the data from directly from the tables instead of joining data I already have. But that's just the way I personally like it :)
这篇关于如何编写SQL查询来计算与其父装配一起出售的零部件数量?(Postgres 11/递归CTE?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!