如何使用 JOIN and/or UNION in MYSQL 计算不同表中的值?
How do I count values in different tables using JOIN and/or UNION in MYSQL?
我想把这些表中的 product_name
数在一起:
jan_product feb_product
+------------+ +------------+
|product_name| |product_name|
+------------+ +------------+
|A | |A |
+------------+ +------------+
|A | |B |
+------------+ +------------+
|C | |C |
+------------+ +------------+
我希望我的结果看起来像:
+------------+---------+---------+
|product_name|jan_count|feb_count|
+------------+---------+---------+
|A |2 |1 |
+------------+---------+---------+
|B |0 |1 |
+------------+---------+---------+
|C |1 |1 |
+------------+---------+---------+
所以我尝试了下面的查询(我正在使用 MYSQL 所以我不能尝试 FULL JOIN):
SELECT
j.product_name,
count(j.product_name) as jan_count,
count(f.product_name) as feb_count
FROM jan_product as j
JOIN feb_product as f
ON j.product_name = f.product_name
group by j.product_name
UNION
SELECT
f.product_name,
count(j.product_name) as jan_count,
count(f.product_name) as feb_count
FROM jan_product as j
RIGHT OUTER JOIN feb_product as f
ON f.product_name = j.product_name
group by f.product_name
;
但我得到的是这个:
+------------+---------+---------+
|product_name|jan_count|feb_count|
+------------+---------+---------+
|A |2 |2 | --- A counts for FEB is wrong
+------------+---------+---------+
|B |0 |1 |
+------------+---------+---------+
|C |1 |1 |
+------------+---------+---------+
我不知道如何才能达到预期的结果。
--Please try using below query
-------
WITH cte AS
( SELECT * FROM jan_product
UNION
SELECT * FROM feb_product)
SELECT cte.product_name,
j.Jan_count,
count(f.product_name) as February_count
FROM cte
LEFT JOIN (SELECT product_name,
COUNT(product_name) as Jan_count
FROM jan_product
GROUP BY product_name) j
ON cte.product_name=j.product_name
LEFT JOIN (SELECT product_name,
COUNT(product_name) as Feb_count
FROM feb_product
GROUP BY product_name) f
ON cte.product_name=f.product_name
我们可以使用 Union all 的计数来做到这一点。我宁愿建议您使用带有月份列的 table。
create table jan (pname char(1));
create table feb (pname char(1));
insert into jan values('A'),('A'),('C');
insert into feb values ('A'),('B'),('C');
select
pname,
count(j) jan,
count(f) feb
from
(select pname,pname j,null f from jan
union all
select pname,null,pname from feb) jf
group by pname
pname | jan | feb
:---- | --: | --:
A | 2 | 1
B | 0 | 1
C | 1 | 1
db<>fiddle here
暂时忽略 table 结构...尝试使用 UNION ALL,包括一个额外的列来指示源月份。然后使用条件 SUM 计算每个月的总计。
另见 db<>fiddle
SELECT t.product_name
, SUM( CASE WHEN t.month_number = 1 THEN 1 ELSE 0 END) AS jan_count
, SUM( CASE WHEN t.month_number = 2 THEN 1 ELSE 0 END) AS feb_count
FROM (
SELECT CAST(1 AS UNSIGNED) AS month_number, product_name
FROM jan_product
UNION ALL
SELECT CAST(2 AS UNSIGNED) AS month_number, product_name
FROM feb_product
) t
GROUP BY t.product_name
结果:
product_name | jan_count | feb_count
:----------- | --------: | --------:
A | 2 | 1
C | 1 | 1
B | 0 | 1
话虽如此,您应该 normalize 模型。您可以通过将所有内容存储在一个带有日期(或月 + 年列)的 table 中来大大简化事情,而不是每个月 table .
此外,您似乎正在存储有关特定产品随时间发生的事件 的信息。如果是这样,您应该有一个单独的 table 包含 unique 产品:
ProductId
ProductName
1
Product A
2
Product B
3
Product C
存储产品信息的其他 table 应该存储“产品”table 的唯一 PK(主键)值 - 不是产品名称。例如,如果您有 ProductSales table
| ProductId | SaleDate | Quantity |
|-----------|-------------|----------|
| 1 | 02/01/2022 | 15 |
| 2 | 02/10/2022 | 4 |
| 1 | 02/12/2022 | 3 |
| 3 | 02/01/2022 | 20 |
要按月检索有关销售的信息,您只需要在两个 table
之间进行简单的 JOIN
另见 db<>fiddle
SELECT p.product_name
, year(s.sales_date) AS sales_year
, SUM( CASE month(s.sales_date) WHEN 1 THEN 1 ELSE 0 END) AS jan_sales
, SUM( CASE month(s.sales_date) WHEN 2 THEN 1 ELSE 0 END) AS feb_sales
, SUM( CASE month(s.sales_date) WHEN 3 THEN 1 ELSE 0 END) AS mar_sales
-- ... etc
FROM product p LEFT JOIN product_sales s ON s.product_id = p.product_id
GROUP BY p.product_name
, year(s.sales_date)
;
结果:
product_name | sales_year | jan_sales | feb_sales | mar_sales
:----------- | ---------: | --------: | --------: | --------:
Product A | 2022 | 0 | 2 | 0
Product B | 2022 | 0 | 1 | 0
Product C | 2022 | 0 | 1 | 0
我想把这些表中的 product_name
数在一起:
jan_product feb_product
+------------+ +------------+
|product_name| |product_name|
+------------+ +------------+
|A | |A |
+------------+ +------------+
|A | |B |
+------------+ +------------+
|C | |C |
+------------+ +------------+
我希望我的结果看起来像:
+------------+---------+---------+
|product_name|jan_count|feb_count|
+------------+---------+---------+
|A |2 |1 |
+------------+---------+---------+
|B |0 |1 |
+------------+---------+---------+
|C |1 |1 |
+------------+---------+---------+
所以我尝试了下面的查询(我正在使用 MYSQL 所以我不能尝试 FULL JOIN):
SELECT
j.product_name,
count(j.product_name) as jan_count,
count(f.product_name) as feb_count
FROM jan_product as j
JOIN feb_product as f
ON j.product_name = f.product_name
group by j.product_name
UNION
SELECT
f.product_name,
count(j.product_name) as jan_count,
count(f.product_name) as feb_count
FROM jan_product as j
RIGHT OUTER JOIN feb_product as f
ON f.product_name = j.product_name
group by f.product_name
;
但我得到的是这个:
+------------+---------+---------+
|product_name|jan_count|feb_count|
+------------+---------+---------+
|A |2 |2 | --- A counts for FEB is wrong
+------------+---------+---------+
|B |0 |1 |
+------------+---------+---------+
|C |1 |1 |
+------------+---------+---------+
我不知道如何才能达到预期的结果。
--Please try using below query
-------
WITH cte AS
( SELECT * FROM jan_product
UNION
SELECT * FROM feb_product)
SELECT cte.product_name,
j.Jan_count,
count(f.product_name) as February_count
FROM cte
LEFT JOIN (SELECT product_name,
COUNT(product_name) as Jan_count
FROM jan_product
GROUP BY product_name) j
ON cte.product_name=j.product_name
LEFT JOIN (SELECT product_name,
COUNT(product_name) as Feb_count
FROM feb_product
GROUP BY product_name) f
ON cte.product_name=f.product_name
我们可以使用 Union all 的计数来做到这一点。我宁愿建议您使用带有月份列的 table。
create table jan (pname char(1)); create table feb (pname char(1)); insert into jan values('A'),('A'),('C'); insert into feb values ('A'),('B'),('C'); select pname, count(j) jan, count(f) feb from (select pname,pname j,null f from jan union all select pname,null,pname from feb) jf group by pname
pname | jan | feb :---- | --: | --: A | 2 | 1 B | 0 | 1 C | 1 | 1
db<>fiddle here
暂时忽略 table 结构...尝试使用 UNION ALL,包括一个额外的列来指示源月份。然后使用条件 SUM 计算每个月的总计。
另见 db<>fiddle
SELECT t.product_name
, SUM( CASE WHEN t.month_number = 1 THEN 1 ELSE 0 END) AS jan_count
, SUM( CASE WHEN t.month_number = 2 THEN 1 ELSE 0 END) AS feb_count
FROM (
SELECT CAST(1 AS UNSIGNED) AS month_number, product_name
FROM jan_product
UNION ALL
SELECT CAST(2 AS UNSIGNED) AS month_number, product_name
FROM feb_product
) t
GROUP BY t.product_name
结果:
product_name | jan_count | feb_count :----------- | --------: | --------: A | 2 | 1 C | 1 | 1 B | 0 | 1
话虽如此,您应该 normalize 模型。您可以通过将所有内容存储在一个带有日期(或月 + 年列)的 table 中来大大简化事情,而不是每个月 table .
此外,您似乎正在存储有关特定产品随时间发生的事件 的信息。如果是这样,您应该有一个单独的 table 包含 unique 产品:
ProductId | ProductName |
---|---|
1 | Product A |
2 | Product B |
3 | Product C |
存储产品信息的其他 table 应该存储“产品”table 的唯一 PK(主键)值 - 不是产品名称。例如,如果您有 ProductSales table
| ProductId | SaleDate | Quantity |
|-----------|-------------|----------|
| 1 | 02/01/2022 | 15 |
| 2 | 02/10/2022 | 4 |
| 1 | 02/12/2022 | 3 |
| 3 | 02/01/2022 | 20 |
要按月检索有关销售的信息,您只需要在两个 table
之间进行简单的 JOIN另见 db<>fiddle
SELECT p.product_name
, year(s.sales_date) AS sales_year
, SUM( CASE month(s.sales_date) WHEN 1 THEN 1 ELSE 0 END) AS jan_sales
, SUM( CASE month(s.sales_date) WHEN 2 THEN 1 ELSE 0 END) AS feb_sales
, SUM( CASE month(s.sales_date) WHEN 3 THEN 1 ELSE 0 END) AS mar_sales
-- ... etc
FROM product p LEFT JOIN product_sales s ON s.product_id = p.product_id
GROUP BY p.product_name
, year(s.sales_date)
;
结果:
product_name | sales_year | jan_sales | feb_sales | mar_sales :----------- | ---------: | --------: | --------: | --------: Product A | 2022 | 0 | 2 | 0 Product B | 2022 | 0 | 1 | 0 Product C | 2022 | 0 | 1 | 0