2014-06-17 106 views
2

我有一个查询如何获得列值不等于零的平均值?

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”。

我怎样才能得到它只能算一个等级,其中等级[X]不等于“0”? 它仍然会计数,除了除以5之外,它会将它除以有多少列不是'0'。

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

+3

如果您标准化架构你的生活会更容易些:你应该是在它自己的子表中的每个等级在一个单独的行 – Bohemian

+0

具体表达取决于是否我们保证“重复组”是ratingN永远是非NULL还是取决于如何处理来自'cast(ratingN As Float)'的NULL值。 – spencer7593

回答

1

尝试使用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

正如其他人所说,你应该考虑如果可能的话你的正常化表。

+1

在第二个查询中,使用CROSS APPLY [大幅简化代码](http://sqlfiddle.com/#!3/570fa/35“SQL小提琴演示”)。 –

+0

@AndriyM更新,谢谢 – FuzzyTree

2

这是不漂亮但应该工作:

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 ... 

做这样的事情之一后应该感到赞赏,数据标准化。

+0

看来这个表达式可能不会返回指定的结果NULL或负值为ratingN。如果我们保证所有的ratingN值都是非空和非负的,这个表达式就行。 (并且在除数为零的边缘情况下,MySQL不会抛出“除以零”错误;这可能取决于sql_mode的设置。) – spencer7593

+0

@ spencer7593 - 确定。 '当评级不为零且评级> 0或'当CAOLESCE(评级,0)> 0“时。 OP使用SQL Server 2008,而不是MySql。 –

+0

或者**当等级1 <> 0 ** **就足够了。 – spencer7593