How to find rows in SQL / MySQL with ORDER BY - mysql

I have a table user
Name | Poin
==================
user1 | 20
user2 | 30
user3 | 80
user4 | 60
user5 | 10
user6 | 85
And I have SQL query
SELECT *
FROM user
ORDER BY poin
It would appear that the data sequence based on points.
But what I need is data like this (for example, I was user1):
Position 1 : user6 - 85 point
Position 2 : user3 - 80 point
Position 3 : user4 - 60 point
You are position 5 : user1 - 20 point
UPDATE
I use this sql
SELECT x.name,
x.position
FROM (SELECT t.user,
#rownum := #rownum + 1 AS position
FROM user t
JOIN (SELECT #rownum := 0) r
ORDER BY t.poin DESC) x
WHERE x.user = 'user1'

This will give current rank for user1:
SELECT count(*) AS rank
FROM user
WHERE poin >= (SELECT poin FROM user WHERE name = 'user1')
Small issue with this query is that if another user has the same points, it will be assigned the same rank - whether it is correct, it is questionable.
If you want to simply add rank for every user, use this:
SELECT
#rank:=#rank+1 AS rank,
name,
poin
FROM user,
(SELECT #rank:=0) r
ORDER BY poin DESC
You can use small variation of this query to get rank of single user, but avoid issue of the same ranking ambiguity:
SELECT *
FROM (
SELECT
#rank:=#rank+1 AS rank,
name,
poin
FROM user,
(SELECT #rank:=0) r
ORDER BY poin DESC
) x
WHERE name = 'user1'

select * from user order by poin desc
Hope this helps

SELECT * FROM user ORDER BY poin DESC
The ORDER BY keyword is used to sort the result-set by a specified column.
The ORDER BY keyword sorts the records in ascending order by default.
If you want to sort the records in a descending order, you can use the DESC keyword.
SQL ORDER BY Syntax
SELECT column_name(s)
FROM table_name
ORDER BY column_name(s) ASC|DESC

SELECT Name,
Poin,
#rowNum := #rowNum + 1 AS position
FROM user
JOIN (SELECT #rowNum := 0) r
ORDER BY poin;

The following code:
SELECT count(*) AS rank
FROM user
WHERE poin >= (SELECT poin FROM user WHERE name = 'user1')
Has a problem when is has double point in different rows.

SELECT Name,
Poin,
#rowNum := #rowNum + 1 AS position
FROM user
JOIN (SELECT #rowNum := 0) r
ORDER BY poin DESC;

Related

MySQL - Rank user amongst list of top high-scores

I have a MySQL query that selects the players with the top 3 highest scores in my users table, then creates an extra column where their rank is assigned:
SELECT s.*, #curRank := #curRank + 1 AS rank
FROM users AS s
JOIN
( SELECT DISTINCT highscore
FROM users
ORDER BY highscore DESC
LIMIT 3
) AS lim
ON s.highscore = lim.highscore
, (SELECT #curRank := 0) r
ORDER BY s.highscore DESC ;
Current progress
So, if the table looked like this:
userid name highscore
0 sam 20
1 james 39
2 jack 10
3 harry 46
4 jennie 7
The result of the query would be this:
userid name highscore rank
3 harry 46 1
1 james 39 2
0 sam 20 3
Question
How could I alter this query so it also display's the user and their rank in the list of results? E.g. if $userName = "jenny", how could I return:
userid name highscore rank
3 harry 46 1
1 james 39 2
0 sam 20 3
4 jenny 7 5 <-- Add this row and skip jack
Edit: I should mention - I am using MySQL version 5.0.96
For versions prior to 8.0...
SELECT *
FROM
( SELECT a.*
, #i := #i+1 i
FROM my_table a
JOIN (SELECT #i:=0) vars
ORDER
BY highscore DESC
, userid
) x
WHERE name = 'jennie'
OR i <= 3
ORDER
BY i;
https://www.db-fiddle.com/f/hYsiCE1bXeTnR2HzoJkKiR/0
If using MySQL 8+, then the RANK analytic function makes this easy:
WITH cte AS (
SELECT *, RANK() OVER (ORDER BY highscore DESC) rnk
FROM users
)
SELECT userid, name, highscore, rnk
FROM cte
WHERE rnk <= 3;
Try this,
select * from (
(select t1.userid,t1.name,t1.highscore,#rank1:=#rank1+1 'rank'
from (SELECT userid, name, highscore FROM users order by highscore desc) t1
join (select #rank1:=0) r
limit 3)
union
(select t2.userid,t2.name,t2.highscore,t2.rank from (select t1.userid,t1.name,t1.highscore,#rank2:=#rank2+1 'rank'
from (SELECT userid, name, highscore FROM users order by highscore desc) t1
join (select #rank2:=0) r) t2
where t2.name='jennie')) t;

reverse the serial number of a grouped query

The following query orders votes based on how many times users voted... I would like to know the # in the queue of the specific user.
SELECT #s:=#s+1 serial_number, user_id, COUNT(slug_owner) as cnt
FROM `votes_queue`,(SELECT #s:= 0) AS s
GROUP BY slug_owner
ORDER BY cnt DESC
serial_number | user_id | cnt 
3 | 19 | 8
2 | 14 | 4
1 | 13 | 2
Essentially i need the numbers in the serial_number column to be reversed so I can tell that user 13 is #3 based on votes ..
Assign the serial numbers after generating the ordered count:
SELECT #s:=#s+1 serial_number, temp.*
FROM (
SELECT user_id, COUNT(slug_owner) as cnt
FROM `votes_queue`,
GROUP BY slug_owner
ORDER BY cnt DESC
) temp, (SELECT #s:= 0) AS s
The serial numbers are not reversed because GROUP BY and variables don't mix. An ORDER BY is fine. You can use #hjpotter92's solution, but the following also fixes the problem:
SELECT (#rn := #rn + 1) as serial_number, t.*
FROM (SELECT serial_number, user_id, COUNT(slug_owner) as cnt
FROM `votes_queue`
GROUP BY slug_owner
) t CROSS JOIN
(SELECT #rn := 0) params
ORDER BY cnt DESC;
I think the performance is the same. I am offering this answer just to clarify what the actual problem is.

Mysql calculate rank based on level DESC and experience DESC

Basically I have a table named hiscores where I want to search a nickname of one user and get his current rank, since the rank rown doesn't exist because the ranks are organized by lvl DESC and then by Experience , so I want a sql query where I search the name of that
"player1" and it returs me rank 2. or input healdeal and get rank 1
Table = hiscores
id - nickname- lvl - experience
1 - healdeal - 99 - 1000
2 - philip - 98 - 595
3 - Player1 - 98 - 620
4 - Mindblow - 52 - 35
I have tried the following
SELECT (COUNT(*) + 1) AS rank FROM hiscores WHERE lvl >(SELECT lvl FROM hiscores WHERE nickname="player1")
Assuming this is MySQL, this will work:
select #rownum:=#rownum+1 Rank,
h.*
from hiscores h,
(SELECT #rownum:=0) r
order by level desc, experience desc
SQLFiddle
If this is MS SQL Server 2005 onwards, you can directly use window functions, like so:
select *, rank() over (order by level desc, experience desc) Rank
from hiscores
In either case, if you want to filter by the nickname, you can put the above expression into a subquery and filter that by the nickname i.e.
select * from
(<ranking expression from above>) rankedresults
where nickname = <input>
I see. You are trying to calculate the rank. I think this might do it:
select count(*) as rank
from hiscores hs cross join
(select hs.*
from hiscores
where nickname = 'player1'
) hs1
where hs.lvl > hs1.lvl or
hs.lvl = hs1.lvl and hs.experience >= hs1.experience;
Actually, if you have ties on both experience and lvl, then this might be a better rank:
select 1 + count(*) as rank
from hiscores hs cross join
(select hs.*
from hiscores
where nickname = 'player1'
) hs1
where hs.lvl > hs1.lvl or
hs.lvl = hs1.lvl and hs.experience > hs1.experience;
If you are using MSSQL 2005+. You can do this:
Test data:
DECLARE #tbl TABLE(id INT,nickname VARCHAR(100),lvl INT, experience INT)
INSERT INTO #tbl
VALUES
(1 ,'healdeal',99,1000),
(2 ,'philip',98,595),
(3 ,'Player1',98,620),
(4 ,'Mindblow',52,35)
Query
;WITH CTE
AS
(
SELECT
RANK() OVER(ORDER BY lvl DESC,experience DESC) AS rank,
tbl.*
FROM
#tbl AS tbl
)
SELECT
*
FROM
CTE
WHERE
CTE.nickname='Player1'
Output
2 3 Player1 98 620

MySQL ranking with GROUP BY and SUM

I have a point table with some columns being:
| user_id | points |
--------------------
| 1 | 10 |
| 5 | 10 |
| 5 | 50 |
| 3 | 15 |
| 3 | 10 |
I would like to get the rank for each user with MySQL.
I've seen this post MySQL get row position in ORDER BY but it doesn't have a SUM in it and I can't get it to work with SUM.
I would like to be able to get the rank of a given user_id.
Thanks in advance for your help!
Reminding the OP's question:
I would like to be able to get the rank of a given user_id.
In order to actually perform operations over the #rank you have to user another derived table (yes, it is inefficient, that's why it is better not to handle this in MySQL):
SELECT * FROM (
SELECT s.*, #rank := #rank + 1 rank FROM (
SELECT user_id, sum(points) TotalPoints FROM t
GROUP BY user_id
) s, (SELECT #rank := 0) init
ORDER BY TotalPoints DESC
) r
WHERE user_id = 3
Output
| USER_ID | TOTALPOINTS | RANK |
|---------|-------------|------|
| 3 | 25 | 2 |
The process is basically:
Get the total amounts of points per user
Sort by those total points ranking
Filter once you have the rank (otherwise, the rank will be compromised)
Fiddle here.
Try this::
SELECT #rownum:=#rownum + 1 as row_number,
t.*
FROM (
select user_id, SUM(points) as Addedpoint
from mytable group by user_id order by Addedpoint desc
) t,
(SELECT #rownum := 0) r
You can achieve that with subquery, inside which you should calculate your sum:
SELECT
#rank:=#rank+1 AS rank,
user_id,
total_points
FROM
(SELECT
user_id,
SUM(points) AS total_points
FROM t
GROUP BY
user_id) AS sum_points
CROSS JOIN
(SELECT #rank:=0) AS init
ORDER BY
sum_points.total_points DESC
-see my fiddle.
select
#rownum := #rownum + 1 AS position,
user_id,
total_points
from
(select user_id, sum(points) as total_points from table)a
join
(SELECT #rownum := 0) r
order by total_points desc
Using a user variable you can do something like this:-
SELECT user_id, tot_points, #Rank:=#Rank + 1 AS user_rank
FROM
(
SELECT user_id, SUM(points) AS tot_points
FROM SomeTable
GROUP BY user_id
ORDER BY tot_points DESC
) Sub1
CROSS JOIN (SELECT #Rank:=0) Sub2
http://sqlfiddle.com/#!2/d0be9/1
SET #rank=0;
select #rank:=#rank+1 AS rank, pointsScored.user_id, sumPoints
from (
select user_id , SUM(points)as sumPoints
from point
group by user_id
order by sumPoints desc
)as pointsScored

mysql Ranking system based on user id

I have a question about the query originally from http://jimmod.com/blog/2008/09/displaying-row-number-rownum-in-mysql/
SELECT IF(#points=p.points, #rownum, #rownum:=#rownum+1) rank,
p.*, (#points:=p.points) dummy
FROM `ranking` p, (SELECT #rownum:=0) x, (SELECT #points:=0) y
ORDER BY `points` DESC
Result of the query is:
rank user_id name score
-----------------------
1 4 Barney 100
2 2 Ted 88
3 1 Marshall 76
3 3 Robin 76
4 5 Lily 68
How can I get the same rank result based on user id?
Query below is based on user id, but the rank of Robin will be 4, not 3 like it should be.
SELECT rank FROM (SELECT #rownum:=#rownum+1 rank, p.*
FROM `ranking` p, (SELECT #rownum:=0) r
ORDER BY `points` DESC) a WHERE a.user_id = 3
Without testing it, seems like this should work using a subquery:
SELECT rank
FROM (
SELECT IF(#points=p.points, #rownum, #rownum:=#rownum+1) rank,
p.*, (#points:=p.points) dummy
FROM `ranking` p, (SELECT #rownum:=0) x, (SELECT #points:=0) y
ORDER BY `points` DESC
) t
WHERE user_id = 3
Your query above displays 4 because you're not using RANK, but rather just ROW NUMBER, and Robin shows up after Marshall (even though they have the same score).
Good luck.