Rank Function in MySQL by LeetCode #178 - mysql

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.

Related

MYSQL rank with ties Implementing Problems

I am trying to implement the solution from a four year old solution to a question and not having any success. Here is what I am using:
SELECT NAME,
sum(STaCResults.masterpoints) AS STaCResults.totalMasterpoints,
STaCResults.city_state,
#prev := #curr,
#curr := STaCResults.totalMasterpoints,
#rank := IF(#prev = #curr, #rank, #rank + #i) AS rank,
IF(#prev <> STaCResults.totalMasterpoints, #i:=1, #i:=#i+1) AS counter
FROM STaCResults
GROUP BY NAME
ORDER BY STaCResults.totalMasterpoints desc
The database contains names, city_state and a masterpoint total for the year which gets summed.
Any help would be appreciated.

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

Getting monthly scores in total score query

I have a table with quiz answers. The following query sums up the total for each participant in a given game.
SELECT #prev := #curr,
#curr := totalscore,
#rank := IF(#prev = #curr, #rank, #rank + #i) AS rank,
IF(#prev <> totalscore, #i:=1, #i:=#i+1) AS counter,
user_id, name, totalscore
FROM
(
SELECT scoringtable.user_id, scoringtable.name, sum(scoringtable.score) AS totalscore
FROM
scoringtable
WHERE game='B'
GROUP BY scoringtable.user_id ORDER BY totalscore DESC
)as scoringtable,(SELECT #curr := null, #prev := null, #rank := 1, #i := 0) tmp_tbl
See working example: http://www.sqlfiddle.com/#!9/dd097/2
However, In the table where I show the totals I also want to show the points gained every month by creating a column for each month. I understand that I can get the data with a query like this:
SELECT score AS 'january' FROM `scoringtable` WHERE month=1
but how can I incorporate something similar in the existing query for all 12 months?
You may use case as in the below lines:
SELECT (case when month =1 then score end)
AS 'january'
(case when month = 2 then score end)
AS 'Feb'
FROM scoringtable

Rank based on two columns

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.

How to implement paging in ranking query?

I am trying to implement a ranking with MySQL. I have found a good article about it without using self joins (ranking without self join).
SELECT
score_id, student_name, score,
#prev := #curr,
#curr := score,
#rank := IF(#prev = #curr, #rank, #rank+1) AS rank
FROM
score,
(SELECT #curr := null, #prev := null, #rank := 0) sel1
ORDER BY score DESC
Regarding that I will have a lot of rankings it would be nice to add paging.
First idea was to use LIMIT, but it fails (rank isn't continued, so it starts with one again).
I can't just multiple the page with the limit, because it is possible to have scores multiple times.
How can I achieve paging with the query?
You could possibly do it similar to LIMIT, by adding an outer query, like so:
SELECT score_id, student_name, score, rank
FROM
(SELECT
score_id, student_name, score,
#prev := #curr,
#curr := score,
#rank := IF(#prev = #curr, #rank, #rank+1) AS rank
FROM
score,
(SELECT #curr := null, #prev := null, #rank := 0) sel1
ORDER BY score DESC) AS b
WHERE rank BETWEEN 1 AND 10
Then you could do BETWEEN 11 AND 20, etc. for the subsequent pages. Might not be the best way to do it, but it is one way :)
I found another solution working for me.
I have added a new column rank to the table and calculate the rank with an UPDATE query.
UPDATE score s, (
SELECT
score_id, student_name, score,
#prev := #curr,
#curr := score,
#rank := IF(#prev = #curr, #rank, #rank+1) AS rank
FROM
score,
(SELECT #curr := null, #prev := null, #rank := 0) sel1
ORDER BY score DESC
) r
SET s.rank = r.rank WHERE s.score_id = r.score_id
Now, it is easily possible to limit the result.