How to implement paging in ranking query? - mysql

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.

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.

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.

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

Write results of SQL sub query back to database

I've been playing with this SQL code:
SELECT
id,
#prev := #curr as prev,
#curr := measure as curr,
#rank := IF(#prev > #curr, #rank+#ties, #rank) AS rank,
#ties := IF(#prev = #curr, #ties+1, 1) AS ties,
(1-#rank/#total) as percentrank
FROM
mytable,
(SELECT
#curr := null,
#prev := null,
#rank := 0,
#ties := 1,
#total := count(*) from mytable where measure is not null
) b
WHERE
measure is not null
ORDER BY
measure DESC
I'd like to write the calculated 'percentrank' back to each corresponding row of mytable in a column named "percentile," but I can't recall how to work in my update statement.
I appreciate the help.
Credit to http://code.openark.org/blog/mysql/sql-ranking-without-self-join for the SQL.
To update from a subquery, give the subquery an alias so that it's a derived table. Then use this syntax:
update YourTable
set SomeField = DerivedTable.something
, etc
from YourTable join
(subquery goes here) DerivedTable on YourTable.Whatever = DerivedTable.Whatever
etc