Rank based on two columns - mysql

I need help with a mysql query. The query has to be able to show rank, as in the picture http://s27.postimg.org/loixkzipv/img.png .
If the wins are same, compare against the "diff" column, maintaining list order. Please help with this query. Thank you.
I've tried:
SELECT player, wins, diff, rank
FROM (
SELECT player, wins, diff,
#curRank := IF(#prevRank = diff, #curRank, #incRank) AS rank,
#incRank := #incRank + 1,
#prevRank := diff
FROM tmpPoradi p, (SELECT #curRank := 0, #prevRank := NULL, #incRank := 1) r
ORDER BY diff
DESC) s;
But this function only compares diff, and doesn't reference wins. How do I make it take into account wins as well?

I think that the following query will get the result you need. First you have to calculate rank in a subquery.I think is much simpler than your approach, you just have to sort your results by wins and diff in descending order (supposing the fields are numbers).Then you just select all the results and change order to player desc.
SELECT player, wins, diff,rank from
(
SELECT player, wins, diff, #winrank := #winrank + 1 AS rank
from tmpPoradi,(SELECT #winrank := 0) r
ORDER BY wins DESC,diff DESC
) rt
ORDER BY player
Hope I am not missing anything.

Related

Rank Function in MySQL by LeetCode #178

leetcode #178 RankScores.
I found some information about Rank Function in MySQL, and then I write the below code:
SELECT Score,
CASE
WHEN #prevRank = Score Then #Rank
WHEN #prevRank:= Score Then #Rank := #Rank +1
END AS rank
FROM Scores s, (SELECT #Rank:=0,#prevRank :=NULL) r
ORDER BY Score DESC;
but I don't know what's the meaning of #prevRank:= Score.
If #prevRank = Score, case will enter first branch if #prevRank equal Score
Else
#prevRank := Score will put score into #prevRank variable AND add #rank + 1, in the same time.

MySQL Select row from a select

I really don't know how to ask this question
But I wanna select a row from a select command
So... I did a command that sorts every xp value from low to high and gives it a rank
SELECT id, xp, #curRank := #curRank + 1 AS rank FROM xp p, (SELECT #curRank := 0) r ORDER BY xp DESC;
If I have id value can I check the row it's in? and then find the rank value?
Cause I mean the value is in a select is there even a way to select from a select
Thank you for the help!
You need to build a subquery, so the DB can first calculate the rank and afterwards you can select it
select rank
from
(
SELECT id, xp, #curRank := #curRank + 1 AS rank
FROM xp
CROSS JOIN (SELECT #curRank := 0) r
ORDER BY xp DESC
) tmp
where id = 123

Ranking order with having same rank repeating to the same level rank category

I am little new to sql and I need to rank my votes table based on votes assigned to each person and rank should be same for the similar votes.
My table would be like
CREATE TABLE votes ( name varchar(10), votes INT );
INSERT INTO votes VALUES
('Ann',100), ('Jones',151), ('Smith',100), ('Rose',240), ('Lee',500), ('Adhams',500);
In my display rows I need to have the rank column first and it should display the rank based on the highest number of votes. Importantly same number of votes need to have the same rank.
I have tried it several times and failed to do it...
Please help me
thanks
You can try below code. There are many links available which would be easily find your answer if you have carefully searched.
SET #rank=0;
SET #votes=0;
select x.rank as rank, x.name as name, x.votes as votes
from(
select #rank:=if(#votes=votes,#rank, #rank +1)AS rank,
#votes := votes,
v.name,
v.votes
from votes v
order by v.votes desc) as x;
To generate RANK, you first need a row number in the order of decreasing votes (variable #rn) and then based on the previous value of vote, create rank (variable #rank).
Try this:
SELECT v.*,
#rank := if((#rn := #rn + 1) is not null,
if (#votes = votes,
#rank,
if ((#votes := votes) is not null, #rn, 1)
),1
) rank
FROM votes v
CROSS JOIN (
SELECT
#votes := NULL,
#rank := 0,
#rn := 0
) t
ORDER BY v.votes DESC;
Demo
About this:
(#rn := #rn + 1) is not null
Since, the expression #rn := #rn + 1 can't be null, we use it to our advantage by not duplicating the whole logic twice.
You can use variables for this:
SELECT #rnk := IF(#v = votes, #rnk,
IF(#v := votes, #rnk + 1, #rnk + 1) AS rnk
name, votes
FROM mytable
CROSS JOIN (SELECT #rnk := 0, #v = :0) AS vars
ORDER BY votes DESC

MySQL get rank from particular row ID

I have list of hospitals under that there are average ratings already calculated. Now I wanted to calculate rank for list of hospitals according to their average ratings from following query
SELECT name,
hospitalID,
currentAvgRating,
#curRank := #curRank + 1 AS rank
FROM hospitals h, (SELECT #curRank := 0) r
ORDER BY currentAvgRating DESC
Now above query works when I want to see all hospitals from table but when I apply WHERE clause like below then result is wrong since with this it takes row position.
SELECT name,
hospitalID,
currentAvgRating,
#curRank := #curRank + 1 AS rank
FROM hospitals h, (SELECT #curRank := 0) r where hospitalID = '453085'
ORDER BY currentAvgRating DESC
Is there any way to get correct result when we apply where clause?
If you proceed what you just found out, logically ("when there is only 1 listitem, it cannot be ordered") - you will come to the conclusion that you NEED to select ALL rows. But nothing wrong with that, you can pack them into a subselect (which isnt even an expensive one) and apply the WHERE to that:
SELECT * FROM (
SELECT name,
hospitalID,
currentAvgRating,
#curRank := #curRank + 1 AS rank
FROM hospitals h, (SELECT #curRank := 0) r
ORDER BY currentAvgRating DESC
) toplist
WHERE toplist.hospitalID = 453085
Wrap in a subquery.
SELECT * FROM (
SELECT name,
hospitalID,
currentAvgRating,
#curRank := #curRank + 1 AS rank
FROM hospitals h, (SELECT #curRank := 0) r
ORDER BY currentAvgRating DESC
)
WHERE hospitalID = '453085'

ranking results of mysql query using AVG

I have a query that ranks results in MySQL:
SET #rank := 0;
SELECT Name, Score, #rank := #rank + 1
FROM Results
ORDER BY Score
This works fine until I try to base the ranking on the average score:
SET #rank := 0;
SELECT Name, AVG(Score) as AvScore, #rank := #rank + 1
FROM Results
ORDER BY AvScore
If I run this I get just the one record back because of the AVG. However, if I add a GROUP BY on Name so that I can get the averages listed for everyone, this has the effect of messing up the correct rankings.
I know the answer's probably staring me in the face but I can't quite get it. How can I output a ranking for each name based on their average result?
You need to use a sub-query:
SET #rank := 0;
SELECT a.name,
a.avscore,
#rank := #rank + 1
FROM (SELECT name,
Avg(score) AS AvScore
FROM results
GROUP BY name) a
ORDER BY a.avscore
You have to order first and then select rank from a derived table:
SELECT Name, AvScore, #rank := #rank + 1
FROM (
SELECT Name, AVG(AvScore) AS AvScore FROM Results
GROUP BY Name ORDER BY AVG(AvScore)
) t1, (SELECT #rank = 0) t2;