【问题标题】:How to select sum -or- 0 if no records exist?如果不存在记录,如何选择 sum -or- 0?
【发布时间】:2012-02-11 21:19:57
【问题描述】:

我需要编写一个查询,返回满足某个条件的所有值的总和,但是如果没有找到行,则该查询需要返回 0,而不是 null。例如:

tab    
+---------------+-----+
| descr         | num |
+---------------+-----+
| hello there   | 5   |
| hi there      | 10  |
| hello         | 10  |
| hi there!     | 15  |
+---------------+-----+

这个查询:

SELECT sum(num) AS val FROM tab WHERE descr LIKE "%hello%";

应该并且确实返回15。然而:

SELECT sum(num) AS val FROM tab WHERE descr LIKE "%greetings%";

应该返回0,但确实返回null

有人可以解释一下吗?

【问题讨论】:

    标签: mysql sum


    【解决方案1】:

    简短的方法是:

    SELECT IFNULL(SUM(num), 0) as val FROM tab WHERE descr LIKE "%greetings%";

    【讨论】:

      【解决方案2】:

      要正确执行此操作,您可能需要区分实际 NULL 导致您求和的数据的情况,以及根本没有要求和的值的情况。

      假设我们有以下内容:

      mysql> select * from t;
      +----------+------+
      | descr    | num  |
      +----------+------+
      | hiya     |    5 |
      | hi there |   10 |
      | yo       | NULL |
      +----------+------+
      

      我们希望空总和为零,但涉及NULL 的总和为NULL。一种(相当痛苦的)方法是:

      mysql> SELECT IF(has_null, NULL, total) AS sum FROM (
          ->    SELECT COALESCE(MAX(num IS NULL), 0) AS has_null, COALESCE(SUM(num), 0) AS total
          ->    FROM t WHERE num < 'ciao')
          -> AS u;
      +------+
      | sum  |
      +------+
      |    0 |
      +------+
      1 row in set, 1 warning (0.00 sec)
      
      mysql> SELECT IF(has_null, NULL, total) AS sum FROM (
          ->    SELECT COALESCE(MAX(num IS NULL), 0) AS has_null, COALESCE(SUM(num), 0) AS total
          ->    FROM t)
          -> AS u;
      +------+
      | sum  |
      +------+
      | NULL |
      +------+
      1 row in set (0.00 sec)
      
      mysql> SELECT IF(has_null, NULL, total) AS sum FROM (
          ->    SELECT COALESCE(MAX(num IS NULL), 0) AS has_null, COALESCE(SUM(num), 0) AS total
          ->    FROM t WHERE descr < 'namaste')
          -> AS u;
      +------+
      | sum  |
      +------+
      |   15 |
      +------+
      1 row in set (0.00 sec)
      
      mysql> SELECT IF(has_null, NULL, total) AS sum FROM (
          ->    SELECT COALESCE(MAX(num IS NULL), 0) AS has_null, COALESCE(SUM(num), 0) AS total
          ->    FROM t WHERE descr > 'namaste')
          -> AS u;
      +------+
      | sum  |
      +------+
      | NULL |
      +------+
      1 row in set (0.00 sec)
      

      也许我还没有想到更好的方法。

      不幸的是,SQL 标准defines SUM to be null when no elements are summed,MySQL 只能遵循该标准。

      【讨论】:

        【解决方案3】:

        检查MySQL documentation for IFNULL

        SELECT SUM(IFNULL(num, 0)) as val FROM tab WHERE descr LIKE "%greetings%";
        

        当然,这假设您的num 字段可以为空并且没有默认值。另一种可能的解决方案是为 num 字段设置默认值 0,这应该可以解决您遇到的问题。

        【讨论】:

        • IFNULL 应该在 SUM 之外,否则如果没有找到行将返回 null。
        • SUM 已经忽略了 NULL 值。在所有情况下 SUM(IFNULL(abc, 0)) == SUM(abc)
        • @Eloims 您的评论似乎是错误的。我也假设过,但这是错误的,这就是我在这里寻找答案的原因。
        • @ChadBefus 我确实错了。 SUM 将忽略 NULL,但如果列仅包含 null,或者表为空,则返回 NULL。这是一个测试这个的小提琴:db-fiddle.com/f/5hvBkzyMWKYx7mT6hKqKFS/0
        【解决方案4】:

        这行得通:

        SELECT IF(SUM(num) IS NULL, 0, SUM(num)) AS val FROM tab WHERE descr LIKE "%whatever%";
        

        IF() 采用三个参数:(1) 语句,(2) 如果语句为真则应用的值,以及 (3) 如果语句为假则应用的值。

        【讨论】:

          【解决方案5】:

          怎么样:

          SELECT COALESCE(sum(num), 0) AS val FROM tab WHERE descr LIKE "%greetings%";
          

          COALESCE 函数基本上说“返回第一个参数,除非它为 null,在这种情况下返回第二个参数”——在这些场景中非常方便。

          【讨论】:

          • 这实际上并没有达到预期的效果——这也会掩盖NULL,它是num值本身的一部分。
          • 这不起作用。如果没有要聚合的行 coalesce 甚至不会被调用。我不明白这怎么会有 122 票。
          猜你喜欢
          • 1970-01-01
          • 2017-11-06
          • 1970-01-01
          • 2020-04-13
          • 1970-01-01
          • 1970-01-01
          • 2020-02-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多