SQL LEFT JOIN 与返回 NULL 值的 COUNT

Posted

技术标签:

【中文标题】SQL LEFT JOIN 与返回 NULL 值的 COUNT【英文标题】:SQL LEFT JOIN with COUNT that returns NULL values 【发布时间】:2017-10-05 11:04:51 【问题描述】:

我有两个表:一个存储产品 ID,另一个存储每个 product_id 和每个 sale_date 的总销售额

餐桌用品

product_id
----------
1         
2         
3         

餐桌销售

product_id |  sale_date | total
-----------+------------+-------
1          | 2017-01-01 |   1
1          | 2017-02-01 |   1
1          | 2017-03-01 |   1

产品 2 和产品 3 没有销售总额。

我想查询销售表,以便在任何产品 id 没有销售的月份前得到 0。 我想要达到的结果是这样的:

product_id |  month     | total
-----------+------------+-------
1          | 2017-01    |   1
1          | 2017-02    |   1
1          | 2017-03    |   1
2          | 2017-01    |   0
2          | 2017-02    |   0
2          | 2017-03    |   0
3          | 2017-01    |   0
3          | 2017-02    |   0
3          | 2017-03    |   0

现在我做的是这样的:

SELECT DATE_FORMAT(sale_date, "%m-%Y") as month,
       Products.product_id,
       COUNT(Sales.product_id) as total 

  FROM products Products 

LEFT OUTER JOIN sales Sales

             ON Sales.product_id = Products.product_id 

       GROUP BY Products.product_id, month

我得到的是:

product_id |  month     | total
-----------+------------+-------
1          | 2017-01    |   1
1          | 2017-02    |   1
1          | 2017-03    |   1
2          | NULL       |   0
3          | NULL       |   0

当没有任何产品 ID 的销售总额时,我应该修改什么以获得每个月的一行?谢谢

【问题讨论】:

我建议你看看日历表。 考虑处理表示层/应用程序级代码中的数据显示问题,假设您有(例如,作用于有序数组的简单 php 循环)。 没有销售,因此没有转换为月份的日期:因此您必须提供缺少的月份 【参考方案1】:

使用cross join 生成行,然后使用left in 引入值:

select p.product_id, d.sales_date,
       coalesce(s.total, 0) as total
from products p cross join
     (select distinct sales_date from sales) d left join
     sales s
     on s.product_id = p.product_id and s.sales_date = d.sales_date
order by p.product_id, d.sales_date;

注意:这假定您想要的所有日期都在sales 中。我应该指出,您可以使用其他日期来源(如果有的话),或者明确列出它们。

【讨论】:

如果销售数据非常大,“从销售中选择不同的销售日期”可能会很慢,替代方法可能是使用日期表(“日历表”)。 非常感谢你们两位,交叉连接是正确的方向。出于性能原因,我还创建了一个单独的日历表。 我还为性能测试创建了一个单独的日历表:执行时间增加了 40%(销售表有超过 200 万行)。【参考方案2】:

你能试试这个查询吗:

select 
 distinct p.product_id, 
 DATE_FORMAT(sale_date, "%m-%Y") as month,
 if(p.product_id <> s.product_id, 0,total) as total 
 from products p, 
sales s 
order by p.product_id

【讨论】:

以上是关于SQL LEFT JOIN 与返回 NULL 值的 COUNT的主要内容,如果未能解决你的问题,请参考以下文章

Spark SQL中Dataframe join操作含null值的列

SQL中left join on 、right join on、inner join on之间的区别

SQL Server-聚焦LEFT JOIN...IS NULL AND NOT EXISTS性能分析(十七)

sql中 INNER JOIN LEFT JOIN RIGHT JOIN FULL JOIN 中 ON与Where的区别

sql中 INNER JOIN LEFT JOIN RIGHT JOIN FULL JOIN 中 ON与Where的区别

SQL 中left joinright joininner join的区别