如何使用 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