I found some good answers for this question, but I can't really get them to work.
I wan't to get a players rank from a hiscore table.
id name score
1 John 10
2 Linda 5
3 Emmy 25
I want to pass in a name in the query (Linda) and get her rank (She only have 5 points in the table above), and get her rank (nr 3).
I found a similar question with this answer, but don't understand it:
SELECT uo.*,
(
SELECT COUNT(*)
FROM users ui
WHERE (ui.points, ui.id) >= (uo.points, uo.id)
) AS rank
FROM users uo
WHERE id = #id
Thanks in advance
SELECT (COUNT(*) + 1) AS rank FROM hiscore WHERE score > (SELECT score FROM hiscore WHERE name = 'Linda')
Try this query -
SELECT name, score, rank FROM
(SELECT *, #r:=#r + 1 rank FROM table_name ORDER BY score DESC) t1,
(SELECT #r:=0) t2
WHERE name = 'Linda'
SET #rownum := 0;
SELECT rank, name, score
FROM
(SELECT #rownum := #rownum + 1 AS rank, name, score
FROM players
ORDER BY score DESC)
Related
I am struggling to find an optimal solution for the following problem.
Suppose I have a table 'Table' like this:
id name report_id
1 name1 1
2 name2 3
3 name3 5
4 name1 7
5 name3 8
....................
I want to select for each value in a set: ('name1', 'name2') 10 random unique rows.
Of course it is possible to do with union like:
(SELECT * FROM Table
WHERE
name='name1'
ORDER BY RAND() LIMIT 10)
UNION
(SELECT * FROM Table
WHERE
name='name2'
ORDER BY RAND() LIMIT 10)
But if I have 100 unique names for which I have to select 10 random records - this query is going to be a bit large.
SQLFiddle demo
select ID,NAME,REPORT_ID
from
(
select *, #row:=if(name=#name,#row,0)+1 as rn, #name:=name from
(select *,RAND() as trand from t) t1,
(select #row:=0,#name:='') tm2
order by name,trand
) t2
where rn<=10
Try this:
SELECT
id,
name,
report_id
FROM
(
SELECT id,
report_id,
name,
CASE WHEN #name != name THEN #rn := 1 ELSE #rn := #rn + 1 END rn,
#name:=name
FROM (SELECT * FROM tbl ORDER BY RAND()) a,
(SELECT #rn:=0, #name := NULL) r
ORDER BY name
) s
WHERE rn <= 10;
SQL FIDDLE DEMO
This doesn't work in MySQL, but in PostgreSQL you can use partition by
select name,report_id from
(select name,report_id,row_number()
over
(partition by name order by random())
as rn from Table) a
where rn<=10
I had this same question and found this answer from a colleague.
I'm building a rank system, I have many horses and on the horse profiles I want to echo the rank of the horse depending on the amount of wins. 1st, 2nd, 3rd etc.
This is my MySQL table containing the horses, in PHP how would I count the rows to get the rank of the horse?
Here's my table, for instance if I was on "Pauls" profile, how would I echo out that he is in 4th position in the global ranking?
1.
select h.*, #rownum := #rownum + 1 AS rank
from horses h, (SELECT #rownum := 0) r
order by h.first DESC, h.second DESC, h.third DESC
2.
SELECT * FROM
(
select h.*, #rownum := #rownum + 1 AS rank
from horses h, (SELECT #rownum := 0) r
order by h.first DESC, h.second DESC, h.third DESC
) t
WHERE id = 428
Two queries to get position of your search record
set #name='Paul',#nr = 0, #namenr = 0;
select #namenr as nr from
(SELECT #nr:=#nr+1,if(name=#name, #namenr := #nr,#namenr=#namenr),name FROM SOME_TABLE order by first DESC ) subsel where subsel.name = #name;
second query will return one record with nr column which you are looking for.
Depending on your scoring system, this could be the right solution for you:
Say your 'first' means 3 points, 'second' means 2 points and and 'third' means 1 point.
This way you can calculate what horse has the most points based on the total.
Example:
Paul has 2 'first', 0 'second' and 1 'third', scoring him to 7 points.
Fletcher has 2 'first', no 'second' and no 'third', scoring him to 6 points.
Calculate the sum of all the points and order it by that field, DESC.
Example query:
SELECT (`first`*3)+(`second`*2)+(`third`*1) AS `total_score` FROM `horses` ORDER BY `total_score` DESC
Additional 'rank' field
SET #rank=0;
SELECT #rank:=#rank+1 AS `rank`, (`first`*3)+(`second`*2)+(`third`*1) AS `total_score` FROM `horses` ORDER BY `total_score` DESC
With the following query you can have your table, and next to it the rank of each horse:
SELECT *,
#curRank := #curRank + 1 AS rank
FROM (SELECT #curRank := 0) r, horses
order by first desc, second desc, third desc
I am using the (SELECT #curRank := 0) to initialize the curRank within the query
Use Order By on multiple columns according to priority.
$sql = "SELECT
#rownum := #rownum + 1 as row_number
FROM horses
CROSS JOIN (SELECT #rownum := 0) r
WHERE name = "Paul"
ORDER BY
first ASC,
second ASC,
third ASC";
now you can obtain the position value from query for any users.
To get the rank of a particular horse, you need only count the number of records that rank above it; sorting by row constructors is a very concise way of accomplishing this:
SELECT COUNT(*) + 1
FROM horses
WHERE (first, second, third)
> (SELECT first, second, third FROM horses WHERE id = ?)
I use this script for my ranking. But I'm not good in MYSQL so maybe someone can help me to change this script to add to this variable:
WHERE id = '$id'
This is what i use:
SELECT id,punkty,
#curRank := #curRank + 1 AS rank
FROM users p, (SELECT #curRank := 0) r
ORDER BY punkty DESC;
I dont know how I can change this script to check one id ? (where id = '$id')
As from comments what i understand the rank given by your query against each user,now you want to know the rank for a given user. You can get the desired rank for the given user's id by doing a sub select
SELECT * FROM (
SELECT id,punkty,
#curRank := #curRank + 1 AS rank
FROM users p, (SELECT #curRank := 0) r
ORDER BY punkty DESC
) t
WHERE id='6';
In below demo if you see the second result set,it shows all the users with their rank and the first query is for one user with id = 6 and his rank is 4 according to the result set of second query
Demo
user_id | date | point
1 20 4
2 20 3
3 20 2
1 21 1
2 21 3
3 21 5
1 23 2
2 23 4
3 23 5
And query:
SELECT user_id, SUM(point) AS point, #row:=#row+1 rank FROM users GROUP BY user_id
How to show rank in this query ?
first you need to delcare #row as variable first
Something like set #row=0; select user_id,SUM(point) as point,#row := #row + 1 as rank from users GROUP BY user_id order by SUM(point) desc;
try this
SET #row=0;
SELECT user_id, SUM(point) AS point, #row:=#row+1 rank FROM users GROUP BY user_id
You can work around the declaring part using this way:
SELECT user_id, SUM(point) AS point, #row:=#row+1 rank FROM users, (SELECT #row := 0) r GROUP BY user_id
I guess you've to write it like:
SELECT user_id, SUM(point) AS point, #row:=#row+1 AS rank FROM users GROUP BY user_id JOIN (SELECT #row := 0) r;
Try this..
SELECT user_id,points, #row:=#row+1 AS Row
from (
SELECT user_id,
SUM(point) AS points rank
FROM users
GROUP BY user_id
Sort by points);
Should have an AS to alias #row to rank, and an order by on point to get them in the right order to rank:-
SELECT user_id, SUM(point) AS point, #row:=#row+1 AS rank
FROM users
CROSS JOIN (SELECT #row:=0) Sub1
GROUP BY user_id
ORDER BY point DESC
I have a query that gets me a users rank in a table of scores.
SELECT
*
FROM
(SELECT
*, #rank:=#rank + 1 rank
FROM
(SELECT
user_id, SUM(round_total) TotalPoints
FROM
sx14sp_mem_picks
GROUP BY user_id) s, (SELECT #rank:=0) init
ORDER BY TotalPoints DESC) r
WHERE
user_id = 22234
There is a problem with ties. I have a table field "pick_date" that i would like to use to break ties with. The user who made his picks first beats the tie.
Any ideas?
If sx14sp_mem_picks.pickdate is the field to break ties then in the order by sx14sp_mem_picks subquery, add
min( pickdate) asc
This will put the earliest pickdate first - you have to use MIN() bc you need to use an aggregate function given the use of "group by".
You need to order by the pick date in addition to the total points. However, you are talking about multiple rows per user. So, let's take the last pick date:
SELECT *
FROM (SELECT *, (#rank:=#rank + 1) as rank
FROM (SELECT user_id, SUM(round_total) as TotalPoints, max(pick_date) as max_pick_date
FROM sx14sp_mem_picks
GROUP BY user_id
) s CROSS JOIN
(SELECT #rank := 0) init
ORDER BY TotalPoints DESC, max_pick_date asc
) r
WHERE user_id = 22234;