8

I have a table like this:

|Quality|Schedule|Cost Control|
-------------------------------
|7      | 8.5    |10          |
|NULL   | 9      |NULL        |

and I need to calculate the average of each row in the same table so it looks like this:

|Quality|Schedule|Cost Control|AVG|
----------------------------------
|7      | 8.5    |10          |8.5|
|NULL   | 9      |NULL        |9  |

which I have done using the following code:

SELECT r.Quality, r.Schedule, r.CostControl, 
((coalesce(r.quality,0)+
  coalesce(r.schedule,0)+
  coalesce(r.CostControl,0)/3) as Average
FROM dbo.Rating r

Which gives the following table:

|Quality|Schedule|Cost Control|AVG|
----------------------------------
|7      | 8.5    |10          |8.5|
|NULL   | 9      |NULL        |3  |

I know the problem is that the divisor is hard coded in my select statement, but I can't figure out how to make it variable. I tried using a case statement to select an addition column:

select Count(case when(r.quality) > 0 then 1 else 0 end + 
             case when (r.Schedule) > 0 then 1 else 0 end + 
             case when (r.CostControl) > 0 then 1 else 0 end)

But that only gives me one value. I'm out of ideas and facing a pretty tight deadline, so any help would be much appreciated.

3 Answers 3

4

Instead of dividing by 3, use

(CASE WHEN Quality IS NULL THEN 0 ELSE 1 END + 
 CASE WHEN Schedule IS NULL THEN 0 ELSE 1 END + 
 CASE WHEN [Cost Control] IS NULL THEN 0 ELSE 1 END)
Sign up to request clarification or add additional context in comments.

1 Comment

Had to throw in a Nullif to prevent dividing by 0 but otherwise this worked perfectly. Thanks!
2

I would use apply instead :

select *, (select sum(v) / count(v) 
           from ( values (quality), (Schedule), (CostControl) 
                ) tt(v) 
          ) as AVG
from table t;

1 Comment

You can simply put avg now?
2

I would use apply with avg():

SELECT r.Quality, r.Schedule, r.CostControl, v.average
FROM dbo.Rating r CROSS APPLY
     (SELECT avg(val)
      FROM (VALUES (quality), (schedule), (CostControl)) v(val)
     ) v(average);

This requires no subqueries, no long case expressions, generalizes easily to more columns, runs no risk of divide-by-zero . . . and the performance might even be equivalent to the case expression.

1 Comment

This seems to be the cleanest solution, tested and verified that it works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.