MySQL Select row from a select - mysql

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

Related

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

MariaDB/MySQL RANK() implementation

I am working on migration from MS SQL Server to MariaDB 10.0. I have query which use RANK() PARTITION BY. I already created some kind of RANK() implementation on my table but it's not working properly.
The original query was:
RANK() OVER (PARTITION BY visits.id_partner ORDER BY visits.updated_at DESC) AS rank
My implementation for MariaDB/MySQL:
SELECT
...,
(
CASE visits.id_partner
WHEN #currId THEN
#curRow := #curRow + 1
ELSE
#curRow := 1 AND #currId := visits.id_partner
END
) AS rank
FROM
records rec
JOIN visits ON visits.id = rec.id_visit,
(
SELECT
#curRank := 0,
#currId := NULL
) r
WHERE
...
ORDER BY visits.id_partner ASC, visits.updated_at DESC
I want to select row ranked by id_partner order by updated_at field. When id_partner is same as on row before RANK should increase by 1. When is different than before, it should reset to 1.
But my query is not working at all. I have still rank 1 on all rows. Can you help me find mistake?
Thank you for help!
It is tricky to use variables in MySQL/MariaDB. A variable should only be used and assigned in one statement (as you do correctly). However, AND can short-circuit variable assignment.
I use a construct like this for ROW_NUMBER(). RANK() is actually a bit of a pain . . . DENSE_RANK() and ROW_NUMBER() are simpler. However, this seems to be the code that you are aiming for:
SELECT ...,
(#rn := if(#currId = visits.id_partner, #rn + 1,
if(#currId := visits.id_partner, 1, 1)
)
) as rank
FROM records rec JOIN
visits
ON visits.id = rec.id_visit CROSS JOIN
(SELECT #rn := 0, #currId := NULL) params
WHERE
...
ORDER BY visits.id_partner ASC, visits.updated_at DESC;
EDIT:
In MySQL (and presumably in MariaDB), sometimes variables don't work quite right unless you use a subquery. So, try this:
SELECT . . .,
(#rn := if(#currId = visits.id_partner, #rn + 1,
if(#currId := visits.id_partner, 1, 1)
)
) as rank
FROM (SELECT ...
FROM records rec JOIN
visits
ON visits.id = rec.id_visit
WHERE
...
ORDER BY visits.id_partner ASC, visits.updated_at DESC
) t CROSS JOIN
(SELECT #rn := 0, #currId := NULL) params;

Selecting top ten rows in MySQL

My Table gainfinal consists of three columns-countrycode, year and values. I want to select ten rows with top ten values. First, I created a rank according to values with the following Query.
SELECT countrycode, `values`,
#curRank := #curRank + 1 AS rank
FROM gainfinal CROSS JOIN
(SELECT #curRank := 0) vars
WHERE year = 2000
ORDER By `values` DESC ;
Now, I need to select the top ten rows with the highest rank. How can I do it ?
SELECT countrycode, `values`,
#curRank := #curRank + 1 AS rank
FROM gainfinal CROSS JOIN
(SELECT #curRank := 0) vars
WHERE year = 2000
ORDER By `values` DESC
LIMIT 10;
Use
LIMIT
in SQL so example:
SELECT countrycode, `values`,
#curRank := #curRank + 1 AS rank
FROM gainfinal CROSS JOIN
(SELECT #curRank := 0) vars
WHERE year = 2000
ORDER By `values` DESC
LIMIT 10
you can get 10 rows starting from row 20 using:Limit
LIMIT 10 OFFSET 20 --Equivalent to LIMIT 20, 10
You can also use your rank variable in where statement
...WHERE year = 2000 and #curRank <11;

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;