Reputation: 785
I have one table called 'ratings'
ID RATING
1 5
1 2
2 5
3 1
3 4
3 4
And i want to find the average rating of each restaurant (same id) that is greater than or equal to than the overall average rating (avg rating of all the restaurants combined)
So for example, restaurant ID 1 avg would be 3.5 and restaurant ID 3 would be 3. The overall avg in this case is a 3.5 So the table should return
ID RATING
1 3.5
2 5
This is how I did it so far but I'm not sure how to compare it to the overall average.
SELECT x.id, AVG(x.rating) AS average
FROM ratings
GROUP BY x.rid;
So this returns a table with the average ratings for each restaurant ID, but How do i compare this to the total average of ratings without hardcoding it?
Upvotes: 1
Views: 3589
Reputation: 22661
This is a good use-case for windowed function!
avg(rating) over () as global_avg
will return the overall average as a new column.
Here the solution, using sub queries as well to "split steps":
select * from (
select id, avg(rating) as user_avg, global_avg
from (
select id, rating, avg(rating) over () as global_avg
from notes
)
group by id, global_avg
)
where user_avg >= global_avg
order by id
This is powerful, you could add a new column "country" and calculate the avg by country:
+---+------+-------+
| id|rating|country|
+---+------+-------+
| 1| 5| fr|
| 1| 2| fr|
| 2| 5| it|
| 3| 1| it|
| 3| 4| it|
| 3| 4| it|
| 4| 2| fr|
+---+------+-------+
select * from (
select id, country, avg(rating) as user_avg, country_avg
from (
select id, country, rating, avg(rating) over (partition by country) as country_avg
from notes
)
group by id, country, country_avg
)
where user_avg >= country_avg
order by id
Upvotes: 2
Reputation: 693
If you want the average of the selected ids to be greater than the average of the other ids, you have to take the average of the averages first, so that the average you're comparing each individual average to isn't skewed by one id getting a lot more reported ratings our a lot fewer reported ratings.
e.g. - id:1 gets 1000 ratings of 1, id:2 gets 1 rating of 2, id:3 gets one rating of 3 and id:4 gets 1 rating of 4. In this case, if you just take the average of all ratings, it is slightly more than 1 (this would show ids 2, 3 & 4 as having average ratings higher than 1.x. If you average the ratings for each id first, each id coincidentally has an average rating equal to their id. The average of these ratings is 2.5. This would show that only ids 3 & 4 have a higher average.
SELECT id
, rating
FROM (
SELECT x.id
, AVERAGE(x.rating) AS rating
FROM ratings
GROUP BY x.id
) avgRatings
WHERE rating >= (SELECT AVERAGE(rating) FROM avgRatings)
Upvotes: 1
Reputation: 1269543
I would be inclined to use window functions:
select r.*
from (select r.id, avg(rating*1.0)) as avgr,
sum(sum(rating*1.0)) over () / sum(count(*)) over () as avgavg
from ratings r
group by r.id
) r
where avgr >= avgavg
Upvotes: 0
Reputation: 7880
use having
clause:
SELECT x.id, AVG(x.rating) AS average
FROM ratings x
GROUP BY x.rid
Having AVG(x.rating)>(select AVG(rating) from ratings);
Upvotes: 3