【问题标题】:mysql - Average from 2 field, ignoring zeromysql - 来自 2 个字段的平均值,忽略零
【发布时间】:2016-03-28 20:15:03
【问题描述】:

我正在寻找一个优雅的查询来获得忽略零值的平均值。

示例:我有 2 个值和预期结果:

SELECT X(10,20) AS result
-- expected result: 15

SELECT X(0,20) AS result
-- expected result: 20

SELECT X(10,0) AS result
-- expected result: 10

SELECT X(0,0) AS result
-- expected result: NULL

这是我的尝试:

(val1+val2)/(2-IF(val1,0,1)-IF(val2,0,1))

还有更好的方法吗?

谢谢

【问题讨论】:

  • 对于仅使用内置 MySQL 函数的表达式,这几乎可以达到预期效果。一个小调整:您可以在分母中添加值,而不是从 2 中减去它们。例如(val1+val2)/(IF(val1,1,0)+IF(val2,1,0))
  • @spencer7593 ,缩短它是个好主意!
  • 我看不出让它更优雅。我对ABS(SIGN()) 模式的偏爱可能是由于两件事:1) 处理 NULL 值。使用ABS(SIGN()),我们可以取回 0、1 或 NULL。使用 IF() 函数,我们只会返回 0 或 1。(只需选择最符合您的规范的那个。)和 2) 我早期的保留... Oracle 没有灵活的 IF() 函数。我倾向于使用 DB2、Teradata 和 Oracle 中可用的表达式和函数(在可行的情况下)。 (并且 SIGN 技巧在 Oracle DECODE 中非常方便。)

标签: mysql average


【解决方案1】:

我会这样写:

( val1 + val2 )/( ABS(SIGN(val1)) + ABS(SIGN(val2)) )

我相信这相当于 OP 表达式,它已经看起来和它一样优雅,而无需创建用户定义的函数。

(这只是我个人的偏好,避免从常量“2”中减去。以及额外的“1”和“0”常量。)

如果我必须将此表达式扩展到三个参数:

( val1 + val2 + val3)/( ABS(SIGN(val1)) + ABS(SIGN(val2)) + ABS(SIGN(val3)) )

注意事项:

MySQL SIGN 函数将返回一个整数值,表示数值的“符号”:-101NULL

MySQL ABS 函数将返回一个数字的绝对值,因此将其包裹在 SIGN 函数周围,即 ABS(SIGN(n)) 将返回 01NULLSIGN(ABS(n)) 将返回相同的内容。

如果参数之一为 NULL,则此表达式将返回 NULL。就像 OP 表达式一样。

我不确定这是否更优雅。但我就是这样做的。


如果意图是使 SQL 更短,则只指定一次 val1val2,就像在 OP 示例中一样,这需要一个函数。 MySQL 没有为此提供本机内置函数,因此我们必须定义(创建)一个用户定义的函数。

但是如果我们这样做,我们需要指定参数的数据类型和返回的数据类型(例如BIGINTDECIMAL(M,N)DOUBLE 等),无论我们采用哪种方式,它将有可能进行隐式数据类型转换和舍入/不精确。

如果没有用户定义的函数,val1val2 必须在表达式中包含两次。但我认为这比其他一些提议的表达方式中的四五次要好。

【讨论】:

    【解决方案2】:

    在平均之前使用CASE 来处理其中一列是0 的情况。

    SELECT CASE
            WHEN val1 = 0 AND val2 = 0 THEN NULL
            WHEN val1 = 0 OR val2 = 0 THEN val1 + val2
            ELSE (val1+val2)/2
           END AS avg
    

    【讨论】:

      【解决方案3】:
      select case when val1 = 0 and val2= 0 then null
                       when val1 = 0 and val2 ! = 0 then val2
                       when val1 != 0 and val2= 0 then val1
                       else (val1 + val2 ) /2 
                     end avg
      

      尝试根据你的要求或mysql版本修改

      【讨论】:

        猜你喜欢
        • 2020-12-10
        • 2019-03-30
        • 2015-03-05
        • 1970-01-01
        • 2020-11-03
        • 2021-05-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-19
        相关资源
        最近更新 更多