tags:

views:

88

answers:

5

Hi there,

I'm not sure if this is possible what I'm trying to achieve. I want to get the avg of averaged columns.

SELECT avg(col1), avg(col2), avg(col3) FROM tbl

My Result should be the avg of all three avg columns, is this possible? Something like this

SELECT avg( col1, col2, col3) FROM tbl

doesn't work at MySQL 5.1

+5  A: 
SELECT (AVG(col1) * COUNT(col1) +
        AVG(col2) * COUNT(col2) +
        AVG(col3) * COUNT(col3)) /
       (COUNT(col1) + COUNT(col2) + COUNT(col3))
FROM tbl
Anthony Faull
+1, this will work with nulls as well, but will be accurate only for a relatively large number of total rows compared to rows with nulls (otherwise count(col1)+count(col2)+count(col3) can be significantly less then 3 * count(*) ); here's a further improvement http://stackoverflow.com/questions/2583742/average-of-average-in-one-row/2586543#2586543
Unreason
Unreason, you're quite right. I've updated my answer to give a weighted average.
Anthony Faull
+1  A: 

Basic maths:

SELECT AVG(col1 + col2 + col3) / 3 FROM tbl
Matti Virkkunen
It's only "basic math" if none of the values are null. For example, if one row is (null, 3, 5) then "null + 3 + 5" evaluates to null and the row is essentially ignored.
+3  A: 

Did you try:

SELECT avg( col1 + col2 + col3)/3.0 FROM tbl

You must check that there are no nulls in this columns.

zendar
Sometimes its easier to just have a break and think about it, instead of brute forcing something. Thanks all for clearing my mind.
asrijaal
+3  A: 

Just trying to improve on Anthony and zendar

SELECT (SUM(col1)+SUM(col2)+SUM(col3))/(COUNT(col1)+COUNT(col2)+COUNT(col3))     
FROM tbl

Assumptions:

  • all values have same signifance (weight)
  • there are nulls
  • you always want correct result

Potential problems:

  • for integer inputs AVG does not overflow where SUM does, so an explicit cast might be necessary

EDIT (thanks to redcayuga): If any of the columns is NULL for all rows the above query returns NULL so COALESCE should be applied to SUMs

SELECT (COALESCE(SUM(col1),0)+
        COALESCE(SUM(col2),0)+
        COALESCE(SUM(col3),0))/(COUNT(col1)+COUNT(col2)+COUNT(col3))     
FROM tbl
Unreason
I'm not sure that all values should have the same weight. The original question seems to suggest otherwise.
If one column has null values in every row the expression will evaluate to null. If all rows are null a divide by zero will be attempted.
good point on all NULLs in a column, as for divide by zero - AVG is undefined in that case, if it is that important to return NULL in that case an IF condition can help, but I'll leave that as an exercise for potential user. :)
Unreason
A: 

Just for fun, here's a bit different solution that leaves NULL handling to avg() function:

SELECT avg(colValue) from 
  ( SELECT col1 as colValue from tbl
    UNION ALL
    SELECT col2 as colValue from tbl
    UNION ALL
    SELECT col3 as colValue from tbl
  )

Values from co1l, col2 and col3 are put in one virtual column and then database calculates average.

You don't have to worry about NULL values - database and avg() function will do it for you.

Note: This could be slower than other solutions since it can cause 3 full table scans to create virtual table. Check execution plan.

zendar