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
Related
I will appreaciate any help on this issue. I already spent hours without any real solution.
I have a SQL
SELECT to_place, rank
FROM
(SELECT g1.to_place as to_place, g1.pcount as pcount,
#rank := IF(#current_to_place = g1.to_place, #rank + 1, 1) AS rank,
#current_to_place := g1.to_place
FROM
(select
to_place, count(*) as pcount
from temp_workflows
group by to_place
order by to_place,pcount desc) g1
ORDER BY g1.to_place, g1.pcount DESC) ranked
In table g1, I am grouping my data to find the most common occurrence of to_place.And then I want to rand those occurrences in ascending order (so I can later select top 3 of the most common occurrences per each to_place category.
The issue is that the user-defined variable is unpredictable (#rank is sometimes always 1) which probably is related to the fact that in one statement, I should not reference the same variable (current_to_place). I read a lot about using separate statements etc. but I could find a way to write my statement in a different way. How can I define #current_to_place elsewhere so the result is the same?
Thanks in advance for your help.
I think you should be testing pcount to get rank and you should initialise variables
DROP TABLE IF EXISTS T;
CREATE TABLE T
(to_place int);
insert into t values (1),(2),(2),(3),(3),(3);
SELECT to_place, rank
FROM
(
SELECT g1.to_place as to_place, g1.pcount as pcount,
#rank := IF(#current_to_place <> pcount, #rank + 1, 1) AS rank,
#current_to_place := pcount
FROM
(select
to_place, count(*) as pcount
from t
group by to_place
order by to_place,pcount desc) g1
cross join(select #rank:=0,#current_to_place:=0) r
ORDER BY g1.pcount DESC
)
ranked
+----------+------+
| to_place | rank |
+----------+------+
| 3 | 1 |
| 2 | 2 |
| 1 | 3 |
+----------+------+
3 rows in set (0.016 sec)
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;
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.
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.
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;