【问题标题】:How to get the average value where a column value does not equal zero?如何获得列值不等于零的平均值?
【发布时间】:2014-08-08 02:50:04
【问题描述】:

我有一个问题

Select AVG(((cast(c.rating1 as Float)+ cast(c.rating2 as Float)+cast (c.rating3 as Float)+cast(c.rating4 as Float)+cast(c.rating5 as Float))/5))
From CSEReduxResponses c
Where 
     c.execoffice_date BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, 0, @today)-1, 0)
AND DATEADD(MONTH, DATEDIFF(MONTH, -1, @today)-1, -1)
AND c.execoffice_status =1
AND C.rating1 <> 0 AND C.rating2 <> 0 AND C.rating3 <> 0 AND C.rating4 <> 0 AND 
C.rating5 <> 0

我得到了 1-5 的平均评分,但我也计算了等于“0”的评分。

我怎样才能让它只计算 rating[x] 不等于 '0' 的评级? 它仍然会计数,但除了将其除以 5 之外,它将除以有多少列不是“0”。

我创建了一个http://sqlfiddle.com/#!3/570fa/7>

【问题讨论】:

  • 如果你规范化你的模式,你的生活会更轻松:你有一个“重复组”,它应该在它自己的子表中,每个评级都在单独的行中
  • 具体表达式取决于我们是否保证 ratingN 始终为非 NULL,或者取决于如何处理来自 cast(ratingN As Float) 的 NULL 值。

标签: sql sql-server-2008


【解决方案1】:

不漂亮但应该可以:

  SELECT AVG((... SUM of 5 ratings ...) /
           (CASE WHEN rating1 > 0 THEN 1 ELSE 0 END + 
            CASE WHEN rating2 > 0 THEN 1 ELSE 0 END +
            CASE WHEN rating3 > 0 THEN 1 ELSE 0 END +
            CASE WHEN rating4 > 0 THEN 1 ELSE 0 END +
            CASE WHEN rating5 > 0 THEN 1 ELSE 0 END))
  FROM ...
  WHERE ...

做完这样的事情后,应该对数据规范化感到赞赏。

【讨论】:

  • 看起来这个表达式可能不会返回 NULL 或 ratingN 的负值的指定结果。如果我们保证所有 ratingN 值都是非空且非负的,则此表达式确实有效。 (并且在除数为零的边缘情况下,MySQL 不会抛出“除以零”错误;这可能取决于 sql_mode 的设置。)
  • @spencer7593 - 好的。 WHEN rating IS NOT NULL and rating &gt; 0WHEN CAOLESCE(rating, 0) &gt; 0。 OP 使用 SQL Server 2008,而不是 MySql。
  • 或者,WHEN rating1 &lt;&gt; 0 就足够了。
  • @spencer7593 - 非常正确。
【解决方案2】:

尝试使用VALUES 获取每行非 0 值的平均值。

SELECT
(
    SELECT AVG(rating)
    FROM (VALUES 
        (cast(c.rating1 as Float)), 
        (cast(c.rating2 as Float)), 
        (cast(c.rating3 as Float)), 
        (cast(c.rating4 as Float)), 
        (cast(c.rating5 as Float))
    ) AS v(rating)
    WHERE v.rating <> 0
) avg_rating
From CSEReduxResponses c
Where 
     c.execoffice_date BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, 0, @today)-1, 0)
AND DATEADD(MONTH, DATEDIFF(MONTH, -1, @today)-1, -1)
AND c.execoffice_status = 1

http://sqlfiddle.com/#!3/570fa/26

我从您的WHERE 中删除了以下条件

AND C.rating1 <> 0 AND C.rating2 <> 0 AND C.rating3 <> 0 AND C.rating4 <> 0 AND 
C.rating5 <> 0

因为如果你把它留在里面,你只会计算有 5 个非 0 评级的行的平均值,我猜这不是你的意图。

要获得所有行中非 0 评分的平均值,请将所有非 0 评分的总和除以非 0 评分的总数。

SELECT
    CAST(SUM(sum_rating) as float)/SUM(count_rating)
From CSEReduxResponses c
CROSS APPLY (
    SELECT SUM(rating), COUNT(rating)
    FROM (VALUES 
        (c.rating1), 
        (c.rating2), 
        (c.rating3), 
        (c.rating4), 
        (c.rating5)
    ) AS v(rating)
    WHERE v.rating <> 0
) AS x (sum_rating, count_rating)
Where 
    c.execoffice_date BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-1, 0)
AND DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1)
AND c.execoffice_status = 1

http://sqlfiddle.com/#!3/570fa/35

正如其他人所提到的,如果可能,您应该考虑规范化您的表格。

【讨论】:

猜你喜欢
  • 2012-03-18
  • 2022-08-14
  • 2015-09-11
  • 2020-10-11
  • 1970-01-01
  • 1970-01-01
  • 2020-01-07
  • 1970-01-01
相关资源
最近更新 更多