Reputation: 987
I have these two tables:
popular_song
song_name | rate | country_id
------------------------------
Tic Tac | 10 | 1
Titanic | 2 | 1
Love Boat | 8 | 2
Battery | 9 | 2
country
conutry_id | country
--------------------------
1 | United States
2 | Germany
What I'd like to achieve is to get the most poular song in each country, e.g.:
song_name | rate | country
--------------------------
Tic Tac | 10 | United States
Battery | 9 | Germany
I've tried this query:
SELECT MAX(rate), song_name, country
FROM popular_song ps JOIN country cnt
ON ps.country_id = cnt.country_id
GROUP BY country
But this doesn't work. I've tried looking at questions like "Order by before group by" but didn't find an answer.
Which mysql query could achieve this result?
Upvotes: 0
Views: 115
Reputation: 1269543
There is a trick that you can use with substring_index()
and group_concat()
:
SELECT MAX(rate),
substring_index(group_concat(song_name order by rate desc separator '|'), '|', 1) as song,
country
FROM popular_song ps JOIN
country cnt
ON ps.country_id = cnt.country_id
GROUP BY country;
EDIT:
If you have big tables and lots of songs per country, I would suggest the not exists
approach:
select rate, song country
from popular_song ps join
country cnt
on ps.country_id = cnt.country_id
where not exists (select 1
from popular_song ps2
where ps2.country_id = ps.country_id and ps2.rate > ps.rate
);
Along with an index on popular_song(country_id, rate)
. I recommended the group_concat()
approach because the OP already had a query with a group by
, so the trick is the easiest to plug into such a query.
Upvotes: 2
Reputation: 6969
You can do this with EXISTS like this:
SELECT rate, song_name, cnt.country_id
FROM popular_song ps JOIN country cnt
ON ps.country_id = cnt.country_id
WHERE NOT EXISTS
(SELECT * FROM popular_song
WHERE ps.country_id = country_id AND rate > ps.rate)
It is not specified in the question whether two songs can be returned per country if their rating is the same. Above query will return several records per country if ratings are not unique at country level.
Upvotes: 1
Reputation: 3196
Here is another way I'v learned from @Gordon Linoff. Here is that question you could learn too.
SELECT ps.*,cnt.country
FROM
(SELECT popular_song.*,
@rownum:= if (@c = country_id ,@rownum+1,if(@c := country_id, 1, 1) )as row_number
FROM popular_song ,
(SELECT @c := '', @rownum:=0) r
order by country_id, rate desc) as ps
LEFT JOIN country cnt
ON ps.country_id = cnt.conutry_id
WHERE ps.row_number = 1
This is the way of implementing row_number()(Partition by ...)
window function in MySql.
Upvotes: 1
Reputation: 64466
You can use another self join to popular songs table with the max rating
SELECT ps.*,cnt.country
FROM popular_song ps
JOIN (SELECT MAX(rate) rate, country_id FROM popular_song GROUP BY country_id) t1
ON(ps.country_id = t1.country_id and ps.rate= t1.rate)
JOIN country cnt
ON ps.country_id = cnt.conutry_id
Upvotes: 3