How do I get only the top 5 of rank() in mysql? - mysql

I am trying to limit the rank to just the top 5 by country. Right now it's giving me every track. How do I fix this? Thank you
SELECT
critic_country,
r.artist,
r.title,
RANK() OVER(PARTITION BY critic_country ORDER BY points DESC) AS ranked_songs
FROM rankings AS r
JOIN polls AS p
ON r.title = p.title

Related

How to select only ranks which occur once except the first rank?

I have 2 tables
Table1: student
Table2: problem
Now we need to find out which student has solved how many problems and in the output we need to display student_id, student_name and no_of_prob in descending order of no_of_prob.
If more than one student has equal number of problems then 1. If the no_of_prob is highest among all others then keep all of them. 2. If the no_of_prob is not the highest, then do not keep any of these.
For example, when we group by student_id, we get this
As student_id 2 and 5 have equal no_of_prob but as their no_of_prob is highest, we will keep both student_id 2 and 5. But the student_id 1 and 3 have equal no_of_prob but its not the highest therefore we need to drop both of these. The final table should be like this.
Now i have found out how to get till the table number 3 above but I don't know how am I supposed to keep the 1st rankers but remove lower rankers if repeated. This is my code below
select s.student_id,student_name, count(problem_id) as no_of_prob,
rank() over(order by count(problem_id) desc) as st_rank
from student s inner join problem p on s.student_id = p.student_id
group by s.student_id;
You can use the RANK() function to get the 1st rankers along with rows having count as 1 with the subquery.
SELECT student_id,
student_name,
no_of_prob
FROM (SELECT p.student_id,student_name,
COUNT(*) AS no_of_prob,
RANK() OVER(ORDER BY COUNT(*) DESC) rk
FROM problem p
JOIN student s ON p.student_id = s.student_id
GROUP BY p.student_id,student_name
ORDER BY COUNT(*) DESC) a
WHERE rk = 1 OR no_of_prob = 1
Check Demo Here
Output
Try this query. Hopefully it will be work fine.
SELECT p.student_id,s.student_name,count(*) as no_of_prb
FROM `problem` p
left join student s on p.student_id=s.student_id
group by p.`student_id`
having
no_of_prb not in (select count(*) as total from problem group by student_id having total>1)
OR
no_of_prb = (select count(*) as total from problem group by student_id order by total desc limit 1)
order by no_of_prb desc

Show MAX value with a join

I'm struggling a little with a query I'm trying to build. For a game I want to display the top 10 of scores.
My table looks like this:
player = id, playername, username
score = id, track, car, bestscore, totalscore, player_id (foreign key to player.id)
For the top10 I want to show the playername, the total score, the car and the track.
The current query I have is:
SELECT p.playername, MAX(s.totalscore) totalscore, s.car, s.track
FROM player p
INNER JOIN score s on p.id = s.player_id
GROUP BY p.playername
ORDER BY MAX(s.totalscore) DESC
LIMIT 10
This seems to work fine, except for one problem. If a user has a score of 50 on track 1 with car 1, and then puts a score of 60 on track 1 with car 2, I see car 1 on the query. It does not seem to get the according car of the top score if this user.
I hope it makes sense what I just told.
Thanks in advance!
EDIT:
SELECT p.playername, MAX(s.totalscore) as totalscore, s.car, s.track
FROM (SELECT * FROM score ORDER BY totalscore DESC) s
INNER JOIN player p ON s.player_id = p.id
GROUP BY p.playername
ORDER BY MAX(s.totalscore) DESC
LIMIT 10
This query seems to do the trick. I've been trying around and the result-set is exactly what I mean. Is it any good though? I'm not good at SQL and just because it works doesn't always mean it's good, does it?
When you have a non-aggregated field as part of an aggregated query that isn't in your group by, and has a many to one relationship with the relation on which you are grouping, MySQL gives no guarantee what it will return.
This query would throw an error in another RDBMS. If you care about the top score by (person,car) tuple, just add it to the group by. However, if you want each player to have a max score, regardless of what car was used, you'll need a subquery or a self join.
One way to do it:
SELECT p.playername, s1.totalscore , s1.car, s1.track
FROM player p
INNER JOIN
score s1 on p.id = s1.player_id
WHERE s1.totalscore = ( SELECT MAX(totalscore) FROM score s2 WHERE s2.player_id=s1.player_id)
ORDER BY s1.totalscore DESC
LIMIT 10
You use "Group By" on playername so the other columns will group in "what mysql desides" manner. If you want to get the cars you should add - group by car.
SELECT p.playername, MAX(s.totalscore) totalscore, s.car, s.track
FROM player p
INNER JOIN score s on p.id = s.player_id
GROUP BY p.playername, s.car //added car
ORDER BY s.totalscore DESC
LIMIT 10

SQL request with count() and position

I've looking for answers but haven't found anything that I could apply to my table, or understand.
I've a table called Vote with 2 fields idVotant and idVote (idVotant is the guy who made the vote, and idVote is the guy for who he voted)
If I use this:
SELECT count(idVote) FROM Vote WHERE idVote=6
I get the number of votes that guy n°6 received.
If I use this:
SELECT idVote,count(idVote) AS votes FROM Vote GROUP BY idVote ORDER BY votes DESC
I get the list of all the guys and the number of votes they have.
Now, what I want to do is get the position of each guys, and of a specific one.
The guy n°6 is first because he got more votes, the guy n°2 is second.
And asking the position of a guy like which position is guy n°3 ?
Try this:
SELECT #rownum:=#rownum+1 AS position, u.idVote, u.votes
FROM (
SELECT idVote, count(idVote) AS votes FROM Vote GROUP BY idVote ORDER BY votes DESC
) u,
(SELECT #rownum:=0) r
See the demo here. I have basically wrapped your SQL query inside the rownum query
To find a particular person, use this:
SELECT * FROM (
SELECT #rownum:=#rownum+1 AS position, u.idVote, u.votes
FROM (
SELECT idVote, count(idVote) AS votes FROM Vote GROUP BY idVote ORDER BY votes DESC
) u,
(SELECT #rownum:=0) r
) ranked_vote WHERE idVote=6
Try Following:
SELECT idVote,count(idVote) AS votes,ROW_NUMBER() OVER (ORDER BY count(idVote) desc) AS Rank
FROM Vote
GROUP BY idVote
ORDER BY count(idVote)
DESC
SQLFIDDLE
Hope its helpful.
Edit: (this one addresses tie votes)
SELECT * FROM
(SELECT idVote, Votes, CASE
WHEN #totalvotes = Votes THEN #rank
ELSE #rank := #rank + 1
END AS Ranking, #totalvotes := Votes FROM
(SELECT idVote, count(*) as Votes
FROM Vote
GROUP BY idVote ORDER BY Votes DESC) V
JOIN (SELECT #rank:=0) r) VoteRanking
See my SQLFiddle
And if you want to select specific ranking let's say ranking no.2 just add :
WHERE Ranking=2

MySQL - ordering images by votes

I haven't used pure mySQL for a while now and looks like I forgot it. Sad story.
Now I have 2 tables - images and votes. Images have a unique id, among others. The votes table only has 2 fields - image id and user id.
I'm trying to get the list of images ordered by number of votes and I'm kinda stuck here. The closest I got is this:
SELECT i.uname AS author, i.title, i.time, i.description, i.id, i.extension, v.uid
FROM images as i
LEFT JOIN
votes as v ON i.id = v.iid
Which returns all images with the voter ID. If an image has multiple votes, than it's returned more than once.
Can someone please help me with this query ?
You need to use COUNT and GROUP BY:
SELECT i.uname AS author, i.title, i.time, i.description, i.id, i.extension, COUNT(v.uid)
FROM images as i
LEFT JOIN votes as v ON i.id = v.iid
GROUP BY i.uname, i.title, i.time, i.description, i.id, i.extension
ORDER BY Count(v.uid) DESC
As suggested, you don't have to GROUP BY all your output fields in MySQL -- just use your unique identifier, in this case, i.id.
Try:
SELECT i.uname AS author, i.title, i.time, i.description, i.id, i.extension, count(*) votes
FROM images as i
LEFT JOIN votes as v ON i.id = v.iid
group by i.id
order by 7
(from lowest to highest - add desc after order by 7 to change the sort order to be from highest to lowest.)

Using TOP 5 with COUNT and LEFT JOIN

I've been using the following code, given to me by HansUp (cheers!), and it's been working great:
SELECT g.ID, Count(t.Grade) AS Total
FROM grade AS g
LEFT JOIN (SELECT Grade FROM telephony WHERE [Date] BETWEEN #08/16/2010# AND #08/20/2010#) AS t ON g.ID=t.Grade
GROUP BY g.ID
ORDER BY 2 DESC;
I'm now looking to find the TOP 5 results returned. I thought it would be as simple as:
SELECT **TOP 5** g.ID, Count(t.Grade) AS Total
FROM grade AS g
LEFT JOIN (SELECT Grade FROM telephony WHERE [Date] BETWEEN #08/16/2010# AND #08/20/2010#) AS t ON g.ID=t.Grade
GROUP BY g.ID
ORDER BY 2 DESC;
Unfortunately that's not working.
Does anyone have any ideas.
Thanks
The TOP clause will get you the top based on your first sort field. Since your first sort field is a constant (2) for all records, you get all records. Add the ID field to your ORDER BY clause and you'll only get five records.
SELECT TOP 5 g.ID, Count(t.Grade) AS Total
FROM grade AS g LEFT JOIN (SELECT Grade FROM telephony WHERE [Date] BETWEEN #08/16/2010# AND #08/20/2010#) AS t ON g.ID = t.Grade
GROUP BY g.ID
ORDER BY g.ID, 2 DESC;
If you're actually after the top 5 by Total in descending order, change the SQL to the following:
SELECT TOP 5 g.ID, Count(t.Grade) AS Total
FROM grade AS g LEFT JOIN (SELECT Grade FROM telephony WHERE [Date] BETWEEN #08/16/2010# AND #08/20/2010#) AS t ON g.ID = t.Grade
GROUP BY g.ID
ORDER BY Count(t.Grade) DESC , 2 DESC;
This is top by value, so if multiple records have a total that is the same and it happens to be in the top 5 value of Total, you'll get them all back. If you truly only ever want five records back, you have to sort on a field that is unique.
This should work.
SELECT TOP 5 g.ID, Count(t.Grade) AS Total
FROM grade AS g
LEFT JOIN (SELECT Grade FROM telephony WHERE [Date] BETWEEN #08/16/2010# AND #08/20/2010#) AS t ON g.ID=t.Grade
GROUP BY g.ID
ORDER BY 2 DESC
So far as I can see, this should work:
SELECT TOP 5 g.ID, Count(t.Grade) AS Total
FROM grade AS g
LEFT JOIN (SELECT Grade FROM telephony WHERE [Date] BETWEEN #08/16/2010# AND #08/20/2010#) AS t ON g.ID=t.Grade
GROUP BY g.ID
ORDER BY Count(t.Grade) DESC;
The key point here is that you use the full expression from the SELECT statement when you want to use it in a WHERE or ORDER BY clause.
If you'd just use the Access query grid to write your SQL, you would have gotten the correct results right off the bat (though you'd have to dip into SQL view to write your subquery).