SQL request with count() and position - mysql

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

Related

How do I get only the top 5 of rank() in 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

Find rank with query in MySql

I know that this question is asked also before but i tried all of them but no one works for me because my query is a little bit different because it has sum function in query that needs to get sum and in base of sum to get the rank of the user.
So my question is how to find the rank for single user my table is this:
currently i am trying with this query but this gives me all users.
SELECT u.user_name as userName
, sum(taken_quiz_points) as totalPoints
FROM taken_quiz as q
, users_app as u
WHERE q.taken_quiz_user_id = u.user_id
GROUP
BY taken_quiz_user_id
ORDER
BY totalPoints DESC
First of all, you should use INNER JOIN when you query data from multiple tables.
Also, I don't think it's possible to ORDER BY an alias, you have to repeat the operation of the alias.
If you want to have the rank of a single user you have to add a WHERE condition, like WHERE u.name = "toto" or something.
You should end up with this :
SELECT
u.user_name as userName ,
sum(q.taken_quiz_points) as totalPoints
FROM taken_quiz q
INNER JOIN users_app u ON q.taken_quiz_user_id = u.user_id
WHERE u.name = "toto"
GROUP BY q.taken_quiz_user_id
ORDER BY sum(q.taken_quiz_points) DESC
So you need the whole dataset in order to know the ranking of the person. It's a bit ugly, but you can nest to get the ranking, and then select from the ranked dataset the person you are interested in:-
Select userName, user_rank from
(Select userName,totalpoints ,dense_rank() OVER (Order by totalpoints desc) as user_rank
from (
SELECT u.user_name as userName ,sum(taken_quiz_points) as totalPoints
FROM taken_quiz as q, users_app as u
WHERE q.taken_quiz_user_id=u.user_id GROUP BY user_name,
taken_quiz_user_id) aa
) bb
where userName ='bob'

Creating a ranking column from a queried column in MySQL

I want to build a ranking column into my query--I've found some similar cases on Stack but this one's a little different and I can't quite make it work. I have a single table, EnrollmentX, with two columns, a unique StudentID and a GroupId (for sake of argument, groups 1:3). I need to simultaneously count the number of students in each of these three groups and then rank the the groups by number of students. I've made it as far as the counting:
SELECT
EnrollmentX.GroupId,
COUNT(EnrollmentX.StudentId) AS StudentCnt
FROM EnrollmentX
GROUP BY
EnrollmentX.GroupId
This puts out two columns, one for GroupId, 1:3, and one for StudentCnt, with the correct number of students in each group. What I can't work out is how to use that StudentCnt column after building it to create a third ranking column.
IF you are on mysql 8 there are more readable options.Change the order in the inner query if you want a different rank.
SELECT GroupId, StudentCnt, #Rank:=#Rank + 1 AS rank FROM
(SELECT EnrollmentX.GroupId,
COUNT(EnrollmentX.StudentId) AS StudentCnt
FROM EnrollmentX
GROUP BY
EnrollmentX.GroupId
ORDER BY StudentCnt DESC
) x CROSS JOIN (SELECT #Rank:=0) y
Try this query:
select ex.GroupId, ex.StudentId, exg.cnt from EnrollmentX ex
left join (
SELECT GroupId, COUNT(*) cnt
FROM EnrollmentX
GROUP BY GroupId
) exg on ex.GroupId = exg.GroupId
order by exg.cnt
try it..
SET #Rank = 0;
SELECT #Rank:=#Rank + 1 rank, EnrollmentX.GroupId,
COUNT(EnrollmentX.StudentId) StudentCnt
FROM EnrollmentX
GROUP BY
EnrollmentX.GroupId
ORDER BY StudentCnt DESC;

SELECT count(*) with ORDER BY

I want to ask you, if its correct if i use this ORDER BY in a SELECT COUNT(*)
Orginal: SELECT count(*) AS cnt FROM players WHERE totalpoints>?
Modified: SELECT count(*) AS cnt FROM players WHERE totalpoints>? ORDER BY timeontheserver DESC
In the Orginal query it outputs the players given "rank" in the database.
But i just noticed that some "players" are having the same amount of points and they get kinda reversed. So it should kinda give the player with an higher amount of "timeontheserver" the better "rank".
I hope you could understand this, thank you.
COUNT(*) will give you a number, you'll want to do a group by on the field you're ordering by to get what you want.
SELECT timeontheserver ,count(*) AS cnt FROM players
WHERE totalpoints>? GROUP BY timeontheserver ORDER BY timeontheserver DESC

Limit results on an GROUP_CONCAT() or INNER JOIN

I've perused extensively the other threads talking about limits on group_concat() and inner joins but haven't found my answer, so I guess I'll go ahead and ask it:
I'm developing an existing photo community site. I want to retrieve members who have their birthday on a given day (today) and then retrieve each member's 5 most highly rated photos. But I also only want the 10 "most favorite" birthday members (ie with the highest favorite count). Here's what I have:
SELECT users.user_id, users.user_name,
GROUP_CONCAT(CONVERT(photos.photo_id,char(32))
ORDER BY photos.average_rate) as photo_ids
FROM users
INNER JOIN photos ON photos.user_id=users.user_id
WHERE users.day_of_birth = DATE_FORMAT('2012-04-17', '%m-%d')
AND users.photo_count>0
GROUP BY users.user_id
ORDER BY users.favorite_count DESC, users.photo_count DESC LIMIT 0,10
This does what I want, EXCEPT that I cannot limit the amount of photo_ids to 5. This is a problem since the output will be sent as JSON to the app, and some members have uploaded upwards of 20,000 photos already, leading to an unacceptably long output string. The only "solution" that seems to work for me is setting the sever variable group_concat_max_len to something reasonable that will hold at least 5 ids, but this is very hacky and unreliable. Is there any way to return exactly 5 photo_ids per user with a single query? Or will I need to do a loop in my PHP?
I don't necessarily need the photo_ids in a comma-separated value, I can also ditch the group_concat() approach entirely and do an inner join if that is more feasible. But even there I'm not aware of a way to limit the results to 5.
These advanced ones are what makes me love MySQL :)
SELECT user_id, user_name,
GROUP_CONCAT(CONVERT(photo_id, char(32)) ORDER BY photos.average_rate) as photo_ids
FROM ( SELECT user_id, user_name, photo_id, favorite_count, photo_count,
(case when #user_id = user_id then #rownum := #rownum + 1 else CONCAT(#rownum := 1, #user_id := user_id) end) AS dummy_val
FROM ( SELECT users.user_id, users.user_name, users.favorite_count, users.photo_count, photos.photo_id
FROM users
INNER JOIN photos
ON photos.user_id=users.user_id
WHERE users.day_of_birth = DATE_FORMAT('2012-04-17', '%m-%d')
AND users.photo_count > 0
ORDER BY users.id ASC, photos.average_rate ASC
) AS h,
( #rownum := NULL,
#user_id := NULL
) AS vars
HAVING rownum <= 5) AS h2
GROUP BY user_id
ORDER BY favorite_count DESC, photo_count DESC LIMIT 0, 10
Basicly I get all rows, and throw away all photos which are 6 or higher in calculated rownum.
SELECT u.user_id
, u.user_name
, GROUP_CONCAT(p.photo_id ORDER BY p.average_rate) AS photo_ids
FROM
( SELECT user_id
, user_name
, favorite_count
, photo_count
FROM users
WHERE day_of_birth = DATE_FORMAT('2012-04-17', '%m-%d')
AND photo_count > 0
ORDER BY favorite_count DESC
, photo_count DESC
LIMIT 10
) AS u
INNER JOIN
photos AS p
ON p.user_id = u10.user_id
AND p.average_rate >=
( SELECT pp.average_rate
FROM photos AS pp
WHERE pp.user_id = u10.user_id
ORDER BY pp.average_rate DESC
LIMIT 1 OFFSET 4
)
GROUP BY u.user_id
ORDER BY u.favorite_count DESC
, u.photo_count DESC