【问题标题】:postgresql return 0 if returned value is null如果返回值为 null,postgresql 返回 0
【发布时间】:2012-06-15 22:42:34
【问题描述】:

我有一个返回 avg(price) 的查询

  select avg(price)
  from(
      select *, cume_dist() OVER (ORDER BY price desc) from web_price_scan
      where listing_Type='AARM'
        and u_kbalikepartnumbers_id = 1000307
        and (EXTRACT(Day FROM (Now()-dateEnded)))*24 < 48
        and price>( select avg(price)* 0.50
                    from(select *, cume_dist() OVER (ORDER BY price desc)
                         from web_price_scan
                         where listing_Type='AARM'
                           and u_kbalikepartnumbers_id = 1000307
                           and (EXTRACT(Day FROM (Now()-dateEnded)))*24 < 48
                        )g
                   where cume_dist < 0.50
                 )
        and price<( select avg(price)*2
                    from( select *, cume_dist() OVER (ORDER BY price desc)
                          from web_price_scan
                          where listing_Type='AARM'
                            and u_kbalikepartnumbers_id = 1000307
                            and (EXTRACT(Day FROM (Now()-dateEnded)))*24 < 48
                        )d
                    where cume_dist < 0.50)
     )s

  having count(*) > 5

如果没有可用的值,如何让它返回0?

【问题讨论】:

  • 你确定你的查询格式正确吗?
  • @LucM:这不可能是一个格式良好的查询。 (没有“group by”子句的“have”子句。)
  • 一切正常,除了有时,当不满足规则时,它不会返回任何东西。另外,我怎么能平均分组,我认为不可能||有什么意义?多选from web_price_scan 是单独的选择;不知道这里有什么问题?
  • 可以使用不带group byhaving 子句(默认为单个组)。它充当聚合结果的where 子句。在这种情况下,只有当第一级子查询返回超过 5 行时才会返回这些行。

标签: sql postgresql


【解决方案1】:

(添加此答案是为了为问题提供更简短、更通用的示例 - 不包括原始问题中的所有特定案例的详细信息)。


这里有两个不同的“问题”,第一个是表或子查询是否没有行,第二个是查询中是否有 NULL 值。

对于我测试过的所有版本,postgres 和 mysql 在平均时会忽略所有 NULL 值,如果没有什么要平均,它将返回 NULL。这通常是有道理的,因为 NULL 被认为是“未知的”。如果你想覆盖它,你可以使用 coalesce(如 Luc M 所建议的那样)。

$ create table foo (bar int);
CREATE TABLE

$ select avg(bar) from foo;
 avg 
-----

(1 row)

$ select coalesce(avg(bar), 0) from foo;
 coalesce 
----------
        0
(1 row)

$ insert into foo values (3);
INSERT 0 1
$ insert into foo values (9);
INSERT 0 1
$ insert into foo values (NULL);
INSERT 0 1
$ select coalesce(avg(bar), 0) from foo;
      coalesce      
--------------------
 6.0000000000000000
(1 row)

当然,“from foo”可以替换为“from (...这里的任何复杂逻辑...) as foo”

现在,表中的 NULL 行是否应该计为 0?然后在 avg 调用中必须使用 coalesce。

$ select coalesce(avg(coalesce(bar, 0)), 0) from foo;
      coalesce      
--------------------
 4.0000000000000000
(1 row)

【讨论】:

    【解决方案2】:

    我可以想到两种方法来实现这一点:

    • IFNULL():

      如果表达式为 NULL,IFNULL() 函数返回指定值。如果表达式为 NOT NULL,则该函数返回表达式。

    语法:

    IFNULL(expression, alt_value)

    IFNULL() 示例与您的查询:

    SELECT AVG( price )
    FROM(
          SELECT *, cume_dist() OVER ( ORDER BY price DESC ) FROM web_price_scan
          WHERE listing_Type = 'AARM'
            AND u_kbalikepartnumbers_id = 1000307
            AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
            AND IFNULL( price, 0 ) > ( SELECT AVG( IFNULL( price, 0 ) )* 0.50
                                         FROM ( SELECT *, cume_dist() OVER ( ORDER BY price DESC )
                                               FROM web_price_scan
                                               WHERE listing_Type='AARM'
                                                 AND u_kbalikepartnumbers_id = 1000307
                                                 AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                             ) g
                                        WHERE cume_dist < 0.50
                                      )
            AND IFNULL( price, 0 ) < ( SELECT AVG( IFNULL( price, 0 ) ) *2
                                         FROM( SELECT *, cume_dist() OVER ( ORDER BY price desc )
                                               FROM web_price_scan
                                               WHERE listing_Type='AARM'
                                                 AND u_kbalikepartnumbers_id = 1000307
                                                 AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                             ) d
                                         WHERE cume_dist < 0.50)
         )s
    HAVING COUNT(*) > 5
    
    • COALESCE()

      COALESCE() 函数返回列表中的第一个非空值。

    语法:

    COALESCE(val1, val2, ...., val_n)

    带有查询的 COALESCE() 示例:

    SELECT AVG( price )
    FROM(
          SELECT *, cume_dist() OVER ( ORDER BY price DESC ) FROM web_price_scan
          WHERE listing_Type = 'AARM'
            AND u_kbalikepartnumbers_id = 1000307
            AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
            AND COALESCE( price, 0 ) > ( SELECT AVG( COALESCE( price, 0 ) )* 0.50
                                         FROM ( SELECT *, cume_dist() OVER ( ORDER BY price DESC )
                                               FROM web_price_scan
                                               WHERE listing_Type='AARM'
                                                 AND u_kbalikepartnumbers_id = 1000307
                                                 AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                             ) g
                                        WHERE cume_dist < 0.50
                                      )
            AND COALESCE( price, 0 ) < ( SELECT AVG( COALESCE( price, 0 ) ) *2
                                         FROM( SELECT *, cume_dist() OVER ( ORDER BY price desc )
                                               FROM web_price_scan
                                               WHERE listing_Type='AARM'
                                                 AND u_kbalikepartnumbers_id = 1000307
                                                 AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                             ) d
                                         WHERE cume_dist < 0.50)
         )s
    HAVING COUNT(*) > 5
    

    【讨论】:

    • IFNULL() 不是 Postgres 中的函数。这可能适用于其他数据库,但问题专门针对 Postgres。
    【解决方案3】:

    使用coalesce

    COALESCE(value [, ...])
    
    The COALESCE function returns the first of its arguments that is not null.  
    Null is returned only if all arguments are null. It is often
    used to substitute a default value for null values when data is
    retrieved for display.
    

    编辑

    下面是COALESCE 与您的查询的示例:

    SELECT AVG( price )
    FROM(
          SELECT *, cume_dist() OVER ( ORDER BY price DESC ) FROM web_price_scan
          WHERE listing_Type = 'AARM'
            AND u_kbalikepartnumbers_id = 1000307
            AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
            AND COALESCE( price, 0 ) > ( SELECT AVG( COALESCE( price, 0 ) )* 0.50
                                         FROM ( SELECT *, cume_dist() OVER ( ORDER BY price DESC )
                                               FROM web_price_scan
                                               WHERE listing_Type='AARM'
                                                 AND u_kbalikepartnumbers_id = 1000307
                                                 AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                             ) g
                                        WHERE cume_dist < 0.50
                                      )
            AND COALESCE( price, 0 ) < ( SELECT AVG( COALESCE( price, 0 ) ) *2
                                         FROM( SELECT *, cume_dist() OVER ( ORDER BY price desc )
                                               FROM web_price_scan
                                               WHERE listing_Type='AARM'
                                                 AND u_kbalikepartnumbers_id = 1000307
                                                 AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                             ) d
                                         WHERE cume_dist < 0.50)
         )s
    HAVING COUNT(*) > 5
    

    恕我直言,COALESCE 不应与AVG 一起使用,因为它会修改值。 NULL 表示未知,仅此而已。这不像在SUM 中使用它。在此示例中,如果我们将 AVG 替换为 SUM,则结果不会失真。将 0 加到总和上不会伤害任何人,但用 0 计算未知值的平均值,您不会得到真正的平均值。

    在这种情况下,我会在WHERE 子句中添加price IS NOT NULL 以避免这些未知值。

    【讨论】:

    • @Andrew 我试图用你的查询给你一个例子。但我迷路了。我怀疑这个查询是否有效。 from web_price_scan... 好像重复了……
    • 对于那些想知道的人,NULLIF(v1, v2)COALESCE 的作用几乎相反,因为如果v1 等于v2,它会返回NULL
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-19
    • 1970-01-01
    • 2018-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多