查询以将不存在的行包含为 0 值

Posted

技术标签:

【中文标题】查询以将不存在的行包含为 0 值【英文标题】:Query to include non-existent rows as 0 value 【发布时间】:2020-10-08 11:44:11 【问题描述】:

虽然关于 SO 有许多类似的问题,但我找不到任何可以给我所需输出的答案。

情况:表格“purchaseorders”包含具有各种详细信息的 PO。示例记录:

| id | orderId | number | vendorNumber | grossValue | bookingYear |
|----|---------|--------|--------------|------------|-------------|
| 14 | 691     | 1      | 12345        | 152.43     | 2016        |

我想要过去 5 年特定供应商的总和(总价值),包括 0 个值。 所需输出:

当前实际输出:

我对 SQL 的尝试:

SELECT po.bookingYear, IFNULL (sum(po.grossValue),0) FROM purchaseorder as po
LEFT JOIN (select 2016 as yr UNION ALL select 2017 as yr UNION ALL select 2018 as yr UNION ALL select 2019 as yr UNION ALL select 2020 as yr) as years ON po.bookingYear=years.yr
WHERE po.vendorNumber=12345 group by po.bookingYear;

我从一个简单的“WHERE bookingYear IN (...)”开始,但由于过去三年没有记录,因此没有返回任何记录。在这里和谷歌上搜索建议我离开加入一个像上面这样的子查询(虽然可能不像上面那样完全)。

我认为这里最大的问题是,在某些年份我没有某些 字段 的 NULL ,而只是 根本没有记录 em> 那些年对于一些供应商来说。

谁能指出我正确的方向?我的 SQL 似乎有点生疏了。说到:是的:mysql

【问题讨论】:

【参考方案1】:

正确的想法。错误的顺序。年份优先:

SELECT years.yr, COALESCE(SUM(po.grossValue), 0)
FROM (select 2016 as yr UNION ALL select 2017 as yr UNION ALL select 2018 as yr UNION ALL select 2019 as yr UNION ALL select 2020 as yr
     ) years LEFT JOIN
     purchaseorder po
     ON po.bookingYear = years.yr AND
        po.vendorNumber = 12345 
GROUP BY years.yr;

注意查询的其他更改:

vendorNumber 上的过滤现在位于 ON 子句中,而不是 WHERE 子句中。在WHERE 子句中,它将外连接变为内连接。 GROUP BYSELECT 使用years.yrpo.bookingYear 的值可能是 NULL。 我更喜欢 COALESCE(),SQL 标准函数,而不是 IFNULL() 一个定制的 MySQL 函数。

【讨论】:

MySQL 不是唯一支持 IFNULL() 的 DBMS。 @Akina 。 . .它不是标准功能。 SQL 为此提供了一个很好的标准函数COALESCE()。所有真实的数据库都支持这一点。 我同意——而且,我从不使用 IFNULL(你可以搜索我的答案——只有一个包含这个功能,它只是从 OP 中复制粘贴,没有版本),仅限 COALESCE。【参考方案2】:

如果您运行的是 MySQL 8.0,则可以使用递归查询来生成日期。如果你有很多年,这会比union all 少打字:

with years as (
    select 2016 bookingYear
    union all select bookingYear + 1 from years where bookingYear < 2020 
)
select y.bookingYear, coalesce(sum(po.grossValue), 0) grossValue
from years y
left join purchaseorder po on po.bookingYear = y.bookingYear and po.vendorNumber = 12345
group by y.bookingYear

【讨论】:

以上是关于查询以将不存在的行包含为 0 值的主要内容,如果未能解决你的问题,请参考以下文章

mongo 查询某个字段的值不为空列表!

POSTGRES:如何仅在另一个值不存在时选择具有某个值的行,在这种情况下选择另一个值?

threejs setClearColor 将不透明度设置为 0 尽管背景不存在

查询以将在特定地理距离内的行返回到给定行(使用 sql server 2008)

SQLite 查询可能存在值的行?

如何将不存在的部署目标配置为 Octopus Deploy?