ranking results of mysql query using AVG - mysql

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;

Related

Rank each employee based on their merit points from highest to lowest

Create two tables emp_merits (meritid, empid, date, meritpoints),emp1(empid,empname) Each employee will be given merit points every month based on their performance. So same employee can have multiple entries in the table with different meritpoints.
List all the merits received by a specific employee (empid will be input here) between specific dates
Rank each employee based on their merit points from highest to lowest
so far i have tried this query
select empid , sum (meritpoints) as totalmerits , (DENSE_RANK()OVER (PARTITION BY empid ORDER BY meritpoints desc)) AS rank from emp_merit
group by empid,meritpoints
order by empid ,totalmerits desc
You could try this:
SELECT #rownum := #rownum + 1 AS rank, a.*
FROM (
SELECT empid, sum(meritpoints) AS totalmerits
FROM emp_merits
GROUP BY empid
ORDER BY totalmerits) a, (SELECT #rownum := 0) r ;
you probably need your specific dates in the WHERE-clause.
You can implement dense_rank() using variables:
select empid, totalmerits,
(#rn := if(#m = totalmerits, #rn,
if(#m := totalmerits, #rn + 1, #rn + 1)
)
) as rank
from (select empid, sum(meritpoints) as totalmerits
from emp_merit
group by empid
order by totalmerits desc
) e cross join
(select #m := -1, #rn := 0) params;

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

Why returns NULL after running select query the second time

I have select query that selects student scores and ranks them from the highest to the lowest, this mysql query works the first time, but when I run it the second time on phpmyadmin, it returns NULL where it is supposed to show the rank of the student, below is the mysql query;
SELECT #rownum := #rownum + 1 AS rank
, student_name
, avga
FROM `averaga`
WHERE class="Form 1A"
ORDER
BY avga DESC
here is a part snapshot of the results from query results
You need to initialize the variable. I usually do this in query itself:
SELECT (#rownum := #rownum + 1) AS rank, student_name, avga
FROM `averaga` a CROSS JOIN
(SELECT #rownum := 0) params
WHERE class = 'Form 1A'
ORDER BY avga 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'

Find a users position on a ordered SQL table

Is there a way to use the SQL ORDER BY function and then find where a user is on the sorted list as a number
My columns are name and score I want to order by score and then find the users position on the table
select name, score,
#rank := #rank + 1 as rank
from your_table
cross join (select #rank := 0) r
order by score desc