I have a list of players. The players are sorted by points. What I'd like to know is how do I get the ranking number of a CERTAIN player?
This is my code so far (which doesn't work because it seems to have some bugs):
$rank = mysql_query (SET #rank := 0;
SELECT *, #rank := #rank + 1
FROM ava_users
WHERE id = '".$id."'
ORDER BY points DESC);
$rank_res = mysql_fetch_array($rank);
When I try to use my query I get an error message:
mysql_fetch_array() expects parameter 1 to be resource, boolean given in /Users/***/Documents/Arcades/Arc_development/arc_projects/***/arc_dev_website/arc_offline/includes/profile/profile_main.inc.php
$rank = mysql_query (
"SELECT a.*,
(
SELECT COUNT(1)
FROM ava_users b
WHERE (b.points, b.id) >= (a.points, a.id)
) AS rank
FROM ava_users a
WHERE a.`user` = '$id'"
);
Try this:
SELECT `user`, rank
FROM (
SELECT `user`, ( #rank := #rank + 1 ) as rank
FROM ava_users, ( select (#rank := 0 ) ) rnk
ORDER BY points DESC
) ranks
WHERE `user` = '".$id."'
user is a key word, therefore use user in order to check parameters equality.
Also, mysql_query can only execute 1 query at a time.
Related
Trying to rank positions but instead of giving (1,2,3,3,5..) when there is a tie in the 3rd position it gives (1,2,3,4,5...).. Help please
below is the code.. thanks
.............................................................................
SELECT t.*
FROM (SELECT #curRank := IF(#prev= #cur, #curRank, #curRank + 1 ) AS classPosition,student_id, #prev:=#cur, #cur:=SUM(total_marks)
FROM (SELECT m.*
FROM marks m
WHERE classform_name = ? AND term = ? AND academic_year = ? GROUP BY student_id
ORDER BY SUM(total_marks) DESC
) n CROSS JOIN
(SELECT #curRank := 0, #prev:=NULL, #cur:=NULL ) q GROUP BY student_id
) t
WHERE student_id = ?
.............................................................................
You don't need a RANK function. You can always rank rows by joining the table to itself, in which case you get to choose how the order (and rank) is determined.
I've mixing session/# variables and aggregation can be a bit unreliable, but you could simply try changing the order of your select expressions to
student_id, #cur:=SUM(total_marks), #curRank := IF(#prev= #cur, #curRank, #curRank + 1 ) AS classPosition, #prev:=#cur
If this doesn't help, I'd suggest separating your aggregation and ranking. Actually, you're already summing in the subquery, so I am not quite sure why you're not just including the sum in the results from n.
SELECT * FROM (
SELECT #curRank := IF(#prev= #cur, #curRank, #curRank + 1 ) AS classPosition, student_id, #prev:=#cur, #cur:=overall
FROM (SELECT m.*, SUM(total_marks) AS overall
FROM marks m
WHERE classform_name = ? AND term = ? AND academic_year = ?
GROUP BY student_id
ORDER BY overall DESC
) AS n
CROSS JOIN (SELECT #curRank := 0, #prev:=NULL, #cur:=NULL ) AS q
) AS completeRankings
WHERE student_id = ?
Actually, your original query should've had other issues anyway. n would have only included a single random total_marks value for each student_id; making the outer SUM kind of pointless.
Edit - This should allow position progression to "skip" later positions according to ties:
SELECT #curRank := #curRank + 1 AS counter, #prevRank := IF(#prev=#cur, #prevRank, #curRank) AS classPosition
... to omit counter from the final results, you'll have to expand out the * explicitly.
Ranks are a real pain in MySQL.
If you want the rank for a single student with these conditions, I would recommend:
SELECT 1 + COUNT(*)
FROM marks m
WHERE m.classform_name = ? AND m.term = ? AND m.academic_year = ? AND
m.total_marks >= (SELECT m2.total_marks
FROM marks m2
WHERE m2.classform_name = m.classform_name AND
m2.term = m.term
m2.academic_year = m.academic_year
m2.student_id = ?
);;
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'
I have a users table with phase1 and phase2 columns that i need to calculate the users rank in each phase and store it in these fields.
the ranking is calculated based on a different table points where i have the points by phase for each user.
what i am trying to do is
sum all points for each user by phase and calculate his rank based on that
in case the user points are equal compare the sum of grade1 in case that is also equal compare the sum of grade2
update users table with his rank in each phase
here is how my new table look like with some demo data
sql fiddle demo
currently I use the below code to calculate the ranking from my old table where both rank and user info are in the same table
old sql fiddle demo
update users a
join (
select id,
(
select count(distinct total)
from users d
where c.total < d.total
) +1 rank
from users c
) b on a.id = b.id
set a.rank = b.rank
there are analytics function in oracle called as rank() and dense_rank() which can be useful to get your result.
As you are using mysql, I tried to convert those function in mysql equivalent.
You can get the desired result with following query which you can use to update users table. You may have to change it further if for the logic when there is tie on grades as well.
set #pk1 ='';
set #rn1 =1;
set #tot ='';
set #val =1;
SELECT id,
name,
phase,
phasetotal,
denseRank
FROM
(
SELECT id,
name,
phase,
phasetotal,
#rn1 := if(#pk1=phase, #rn1+#val,1) as denseRank,
#val := if(#pk1=phase, if(#tot=phasetotal, #val+1, 1),1) as value,
#pk1 := phase,
#tot := phasetotal
FROM
(
select users.id,users.name, points.phase, sum(points.points)
as phasetotal from users,points where users.id = points.userid
group by users.id, points.phase order by points.phase, phasetotal desc, points.grade1 desc, points.grade2 desc
) A
) B;
Here's the update query
set #pk1 ='';
set #rn1 =1;
set #tot ='';
set #val =1;
UPDATE users u join (
SELECT id,
name,
phase,
phasetotal,
denseRank
FROM
(
SELECT id,
name,
phase,
phasetotal,
#rn1 := if(#pk1=phase, #rn1+#val,1) as denseRank,
#val := if(#pk1=phase, if(#tot=phasetotal, #val+1, 1),1) as value,
#pk1 := phase,
#tot := phasetotal
FROM
(
select users.id,users.name, points.phase, sum(points.points)
as phasetotal from users,points where users.id = points.userid
group by users.id, points.phase order by points.phase, phasetotal desc, points.grade1 desc, points.grade2 desc
) A
) B ) C on u.id = C.id
SET u.phase1 = CASE WHEN C.phase = 1 and u.phase1 = 0 THEN C.denseRank ELSE u.phase1 END,
u.phase2 = CASE WHEN C.phase = 2 and u.phase2 = 0 THEN C.denseRank ELSE u.phase2 END;
I have a leaderboard where i want to give each row a rank for how many points they have. This is the code i have so far. It works fine but when two players have the same amount of points, the rank is the same, for example if there are 2/2 players in the DB where they both have 100 points, both their ranks are 1.
I would like to even if they have same amount of points to give one of them a higher rank, so it would be 1,2.
SELECT id, leaderfirst.pictureid, leaderfirst.point, FIND_IN_SET( leaderfirst.point, (
SELECT GROUP_CONCAT( leaderfirst.point
ORDER BY leaderfirst.point DESC )
FROM leaderfirst )
) AS rank
FROM leaderfirst
leaderboard =
SELECT id,
leaderfirst.pictureid,
leaderfirst.point,
FIND_IN_SET( leaderfirst.point,
( SELECT GROUP_CONCAT(
leaderfirst.point ORDER BY leaderfirst.point DESC ,id)
FROM leaderfirst ) ) AS rank
FROM leaderfirst
Try this.
What you want here is an increment counter in the SQL:
There are two ways of doing this:
First:
set #rownum := 0;
And then
SELECT id, leaderfirst.pictureid, leaderfirst.point,
FIND_IN_SET( leaderfirst.point,
( SELECT GROUP_CONCAT(
leaderfirst.point ORDER BY leaderfirst.point DESC
)
FROM leaderfirst )
) AS rank,
#rownum := #rownum + 1 AS row_number
FROM leaderfirst
ORDER BY row_number
Or:
Combining the first two queries together you can use :
SELECT id, leaderfirst.pictureid, leaderfirst.point,
FIND_IN_SET( leaderfirst.point,
( SELECT GROUP_CONCAT(
leaderfirst.point ORDER BY leaderfirst.point DESC
)
FROM leaderfirst )
) AS rank,
#rownum := #rownum + 1 AS row_number
FROM leaderfirst
CROSS JOIN (select #rownum := 0) r
ORDER BY row_number
Source: This answer here.
There are also various variaton on this theme.
Solution 2:
simply ignore trying to generate this data with your MySQL; you said you don't care about order, simply the auto-increment nature of the resultant ranking; therefore you can do something like this if you're using PHP (and similar work in other languages):
Pseudo-code below:
$mysqlDataOutput = mysql result data from your SQL . "ORDER BY rank DESC";
$counter = 0;
foreach($mysqlDataOutput as $resultRow){
print $counter.") ".resultRow['points']. " -
<img src='".$resultRow['pictureid']."' alt=''>";
$counter++;
}
unset($mysqlDataOutput, $resultRow);
If you want to order the other way around (lowest rank first) then simply invert your SQL ORDER BY and set:
$counter = count($mysqlDataOutput);
foreach(){
...
$coounter--;
}
I have table with id (store user id) and score in different match. I want what is the position of a user.
So for i try this sql fiddle;
in this I am getting all the row but I need only user having id 3 and it position in the table.
like this:
Score Postion
26 3
Even i try to do like this but no success
MySql: Find row number of specific record
With MySQL, how can I generate a column containing the record index in a table?
I got the answer: http://sqlfiddle.com/#!2/b787a/2
select * from (
select T.*,(#rownum := #rownum + 1) as rownum from (
select sum(score) as S,id from mytable group by id order by S desc ) as T
JOIN (SELECT #rownum := 0) r
) as w where id = 3
Updated sqlfiddle and above query. Now it is working perfectly.
I think this should do the trick:
SELECT totalScore, rownum FROM (
SELECT id,sum(score) AS totalScore,(#rownum := #rownum + 1) AS rownum
FROM mytable
JOIN (SELECT #rownum := 0) r
group by id) result
WHERE result.ID = 3;
just add a where clause
select x.id,x.sum,x.rownum
from(
select id,sum(score) as sum,(#rownum := #rownum + 1) as rownum
from mytable
JOIN (SELECT #rownum := 0) r
group by id
) x
where id =3