Selecting top ten rows in MySQL - 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;

Related

What would the equivalent statement be in MySQL 5.6.39?

I recently moved to a shared host that has MySQL 5.6.39 instead of MariaDB 10.x, I was wondering what would the equivalent of the following MariaDB statement in MySQL?
SELECT rank,
total
FROM
(SELECT ROW_NUMBER() OVER (
ORDER BY `prestige` DESC, `xp` DESC) AS rank,
(SELECT COUNT(*)
FROM Modular_LS) AS total,
steamid
FROM Modular_LS) sub
WHERE sub.steamid = '%s'
I got as far as this, but now I'm stuck
SELECT rank, total FROM
(SELECT #rank := #rank +1 as rank FROM Modular_LS,
(SELECT COUNT(*) FROM Modular_LS) AS total, steamid FROM Modular_LS) sub,
(SELECT #rank := 0) r ORDER BY `prestige` DESC, `xp` DESC) t;
The table structure contains the column steamid, xp, prestige
My goal is to order by prestige descending first and then xp descending to put it in a ranking like-order, then using WHERE query to find a specific player's ranking. The output of which contains the rank (position) and the total (total amount of records)
Maybe this will get you started:
SELECT #rank := IF(player_id = #prev, #rank + 1, 1), #prev := player_id
FROM ( SELECT #rank := 1, #prev = 0 ) AS init
JOIN ( SELECT player_id
FROM Modular_LS
ORDER BY prestige DESC, SP DESC
) AS x ;
After a few hours, this is what I came up with that solved my problem.
SELECT
sub.rank
,sub.total
FROM
(
SELECT
t.id
,t.steamid
,#rownum : = #rownum + 1 AS rank
,(
SELECT
COUNT (*)
FROM
Modular_LS
) AS total
FROM
Modular_LS t JOIN (
SELECT
#rownum : = 0
) r
ORDER BY
t.prestige DESC
,t.xp DESC
) sub
WHERE
sub.steamid = '%s'

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

Select recent n number of entries of all users from table

I have a below table and wants to select only last 2 entries of all users.
Source table:
-------------------------------------
UserId | QuizId(AID)|quizendtime(AID)|
--------------------------------------
1 10 2016-5-12
2 10 2016-5-12
1 11 2016-6-12
2 12 2016-8-12
3 12 2016-8-12
2 13 2016-8-12
1 14 2016-9-12
3 14 2016-9-12
3 11 2016-6-12
Expected output is like, (should list only recent 2 quizid entries for all users)
-------------------------------------
UserId | QuizId(AID)|quizendtime(AID)|
--------------------------------------
1 14 2016-9-12
1 11 2016-6-12
2 13 2016-8-12
2 12 2016-8-12
3 14 2016-9-12
3 12 2016-8-12
Any idea's to produce this output.
Using MySQL user defined variables you can accomplish this:
SELECT
t.UserId,
t.`QuizId(AID)`,
t.`quizendtime(AID)`
FROM
(
SELECT
*,
IF(#sameUser = UserId, #a := #a + 1 , #a := 1) row_number,
#sameUser := UserId
FROM your_table
CROSS JOIN (SELECT #a := 1, #sameUser := 0) var
ORDER BY UserId , `quizendtime(AID)` DESC
) AS t
WHERE t.row_number <= 2
Working Demo
Note: If you want at most x number of entries for each user then change the condition in where clause like below:
WHERE t.row_number <= x
Explanation:
SELECT
*,
IF(#sameUser = UserId, #a := #a + 1 , #a := 1) row_number,
#sameUser := UserId
FROM your_table
CROSS JOIN (SELECT #a := 1, #sameUser := 0) var
ORDER BY UserId , `quizendtime(AID)` DESC;
This query sorts all the data in ascending order of userId and descending order of quizendtime(AID).
Now take a walk on this (multi) sorted data.
Every time you see a new userId assign a row_number (1). If you see the same user again then just increase the row_number.
Finally filtering only those records which are having row_number <= 2 ensures the at most two latest entries for each user.
EDIT: As Gordon pointed out that the evaluation of expressions using user defined variables in mysql is not guaranteed to follow the same order always so based on that the above query is slightly modified:
SELECT
t.UserId,
t.`QuizId(AID)`,
t.`quizendtime(AID)`
FROM
(
SELECT
*,
IF (
#sameUser = UserId,
#a := #a + 1,
IF(#sameUser := UserId, #a := 1, #a:= 1)
)AS row_number
FROM your_table
CROSS JOIN (SELECT #a := 1, #sameUser := 0) var
ORDER BY UserId , `quizendtime(AID)` DESC
) AS t
WHERE t.row_number <= 2;
WORKING DEMO V2
User-defined variables are the key to the solution. But, it is very important to have all the variable assignments in a single expression. MySQL does not guarantee the order of evaluation of expressions in a select -- and, in fact, sometimes processes them in different orders.
select t.*
from (select t.*,
(#rn := if(#u = UserId, #rn + 1,
if(#u := UserId, 1, 1)
)
) as rn
from t cross join
(select #u := -1, #rn := 0) params
order by UserId, quizendtime desc
) t
where rn <= 2;

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'

MySQL Query Help Finding Rank by ID

I'm trying to modify the following query to find the rank of a specific videoid and I'm not having much luck can anyone suggest a solution?
SELECT videoid wins/loses as win_loss,
#curRank := #curRank + 1 AS rank
FROM cb_video,
(SELECT #curRank := 0) r
ORDER BY wins/loses DESC
I tried doing a subquery like this but it fails:
SELECT rank
FROM (SELECT videoid wins/loses as win_loss,
#curRank := #curRank + 1 AS rank
FROM cb_video,
(SELECT #curRank := 0) r
ORDER BY wins/loses DESC)
WHERE videoid = 116
Also adding the videoid to the WHERE clause without a subquery just always shows the rank being the #1 position as it only returns one row:
SELECT videoid wins/loses as win_loss,
#curRank := #curRank + 1 AS rank
FROM cb_video,
(SELECT #curRank := 0) r
WHERE videoid = 116
ORDER BY wins/loses DESC
Any ideas how to limit the result to a specific ID but still retain the rank? FYI I keep two columns (wins and loses) if that helps.
SELECT a.videoid,
(SELECT COUNT(*) FROM cb_video b
WHERE a.videoid !=b.videoid
AND (b.wins/b.loses) > (a.wins/a.loses))+1 AS rank
FROM cb_video a
WHERE a.videoid = 116
Try something like this:
SELECT videoid, rank FROM (SELECT videoid, wins/loses as win_loss, #curRank := #curRank + 1 AS rank FROM cb_video, (SELECT #curRank := 0) r ORDER BY wins/loses DESC) s WHERE videoid = 116
I've tested this on simple subset created of similar table as you've described...
It returns the ONE video and its actual final Rank of the entire set...
select *
from ( SELECT
videoid,
wins,
losses,
wins/losses,
#curRank := #curRank +1 Rank
FROM
cb_video,
( select #curRank := 0 ) r
order by
wins/losses desc ) PreQuery
where
PreQuery.VideoID = 116