Find rank of participant in various contests sql - mysql

I have a participant table:
userid name
1 John
2 Sam
3 Harry
And there is contest table:
contestid contestname
1 abc
2 def
3 ghi
Score table looks like this:
id contestid userid score
1 1 1 200
2 1 2 300
3 1 3 250
4 2 1 500
5 2 2 400
6 3 2 800
Now, given an userid, I need to find out his rank in all the contest.
The Rank should be based on Contest and Score.
Output should be like this for userid=1:
contestid rank
1 3
2 1
3 Nil
How can I get this output?

1. If you need it Rank by Score and Contest then try this
SET #rank := 0;
SET #prev := NULL;
SELECT contestid,userid,score,Rank FROM
(
SELECT contestid,userid,score,#rank := IF(#prev = contestid, #rank + 1, 1) AS rank,
#prev := contestid
FROM scores ORDER BY contestid, score DESC
) S Where userid = 1
FIDDLE DEMO
2. If you need it Rank by Score then try this
SELECT contestid,userid,score, FIND_IN_SET( score,
(SELECT GROUP_CONCAT(score ORDER BY score DESC) FROM scores)) AS rank
FROM scores
Where UserId = 1
Fiddle Demo
3. If you want UserName and COntest Name then try this
SELECT C.contestname,P.name,S.score, FIND_IN_SET( S.score,
(SELECT GROUP_CONCAT(score ORDER BY score DESC) FROM scores)) AS rank
FROM scores S Join participant P ON P.userid =C.userid
Join contest C ON C.contestid = S.contestid
Where UserId = 1

Related

MySQL Broken Rank

I have the following query which returns some event details, the number of votes and a rank.
SELECT e.guid,
e.name,
(SELECT COUNT(ev.event_vote_id)
FROM event_vote sv
WHERE ev.event_uid = s.guid) AS votes,
#curRank := #curRank + 1 AS rank
FROM event e, (SELECT #curRank := 0) r
ORDER BY votes DESC
It returns the correct details including votes but the rank is broken.
Actual Result
guid | name | votes | rank
def test2 2 2
abc test1 1 1
ghi test3 0 3
jkl test4 0 4
Expected Result
guid | name | votes | rank
def test2 2 1
abc test1 1 2
ghi test3 0 3
jkl test4 0 4
For some reason test1 has a higher rank than test2.
I assume I need to use a JOIN but i'm unsure on the syntax.
You have to calculate the votes first, then calculate the ranking.
SELECT T.*, #curRank := #curRank + 1 AS rank
FROM ( SELECT e.guid,
e.name,
(SELECT COUNT(ev.event_vote_id)
FROM event_vote sv
WHERE ev.event_uid = s.guid) AS votes
FROM event e
) as T
CROSS JOIN (SELECT #curRank := 0) r
ORDER BY votes DESC
You have wrong result because SELECT section occurs before ORDER section, so you already have a rank but not necessary match the order you get at the end.
Can read more about it here:
Order Of Execution of the SQL query

Mysql select query count until reach the condition

I have lists of users with his points and game id. I need to find the rank of the specified user based on the game order by the maximum lb_point. Below is my table.
lb_id user_id game_id room_id lb_point
------------------------------------------------
1 1 2 1 670
2 1 1 2 200
3 1 2 2 650
4 1 1 1 400
5 3 2 1 700
6 4 2 5 450
7 2 1 3 550
8 2 1 1 100
9 1 1 1 200
I have already done this by using PHP code and its working fine as follows.
$game_id = 2;
$user_id = 1;
$query_rnk = $this->db->query('SELECT user_id AS uid FROM leader_board WHERE game_id = "'.$game_id.'" GROUP by user_id ORDER BY lb_point DESC');
if ($query_rnk->num_rows() > 0){
$j=1;
foreach($query_rnk->result() as $row_rnk){
if($row_rnk->uid == $user_id){
$rnk_status = 1;
break;
}
$j++;
}
if($rnk_status == 1){
$resp['rank'] = $j;
}
}
Answer is: 2.
But i need to find this by using one query. Any idea?
You could do with a select counting the number of rows of a proper select
select count(*)
from (
select distinct user_id
from leader_board
where lb_point >= (select max( lb_point )
from leader_board
where user_id = 1
and game_id = 2 )
and game_id = 2
) t
If you want to get the rank of user_id = 1, try this:
SELECT urank
FROM (
SELECT user_id AS uid, #rank := #rand + 1 AS urank
FROM leader_board
CROSS JOIN (SELECT #rank := 0) t
WHERE game_id = '$game_id'
GROUP by user_id
ORDER BY lb_point DESC
) tmp
WHERE uid = '$user_id'
SELECT count(*)+1 as Rank from (select lb_point from games where game_id =2 order by lb_point DESC) as list where list.lb_point > (select max(lb_point) from games where user_id = 1 and game_id = 2)
This will give the rank 2 for user_id = 1 in game_id = 2 which is the answer you've mentioned in question.

first N row of each id in MySQL

I have a table for my users scores like this:
id | kills
----------
2 | 1
1 | 1
1 | 5
1 | 3
2 | 4
2 | 5
3 | 5
I want to get the first 2 rows of each player which have more than 2 kills. So the result should look like this
id | kills
----------
1 | 5
1 | 3
2 | 4
2 | 5
3 | 5
I tried this but it doesn't work:
SELECT *
FROM user_stats us
WHERE
(
SELECT COUNT(*)
FROM user_stats f
WHERE f.id=us.id AND f.kills > 2
) <= 2;
I suspect that you just want the two largest values for users that have kills > 2. If so, use variables:
select us.*
from (select us.*,
(#rn := if(#i = id, #rn + 1,
if(#i := id, 1, 1)
)
) as seqnum
from user_stats us cross join
(select #rn := 0, #i := -1) params
where us.kills > 2
order by us.id, kills desc
) us
where seqnum <= 2;
select * from user_stats
where (id,kills) in (select id, max(kills) from user_stats where kills > 2 group by id
union
select id, min(kills) from user_stats where kills > 2 group by id)
Try this. I am coming from Oracle, where rownum is a count of rows selected. This should have the same effect.
select #rownum:=#rownum+1, us.*
from user_stats us , (select #rownum := 0) r
where id in (
select id from user_stats f
group by id
having count(*) > 2
)
and #rownum < 3;
based on response of vkp. Take min and max when id has more then 1 kill
select id, max(kills)
from user_stats
group by id
having count(kills) > 2
union
select id, min(kills)
from user_stats
group by id
having count(kills) > 2
order by id

How to get the rank of a row in mysql query

this my database structure
table : players
id | name | score
1 | Bob | 600
2 | Alex | 1400
3 | John | 800
4 | sara | 2000
I need to select john's row and count what is the john' rank OrderBy score
as you see john is 3rd (800) , sara is 1st (2000), Alex is 2nd (1400) in score ranks
Select #rownum := #rownum + 1 AS rank form players where id=3 OrderBy score
any idea ?
You can do it by a subquery and count the players who has score more than the score of a certian id
Select count(*) as rank
from players
where score > (select score from players where id=3)
But if you want to have other information beside the rank you can do it by
SELECT ranks . *
FROM (
SELECT #rownum := #rownum +1 ‘rank’, p.id, p.score
FROM players p, (SELECT #rownum :=0)r
ORDER BY score DESC
) ranks
WHERE id =3
select rank
from
(
Select id, name, #rownum := #rownum + 1 AS rank
from players
cross join (select #rownum := 0) r
Order By score desc
) tmp
where id = 3
Might be easier to do a self join, where the joined table score is greater (to get the rows with a higher score) and just do a count:-
SELECT COUNT(*)
FROM players a
INNER JOIN players b
ON a.score >= b.score
WHERE a.id = 3
Question is what to do with equal scores.

How to rank MySQL results, based on different values?

I have 2 different tables in my database by the name of: rank, settings.
Here is how each table looks like with a few records in them:
Table #rank:
id points userid
-- ----- ------
1 500 1
2 300 2
3 900 3
4 1500 4
5 100 5
6 700 6
7 230 7
8 350 8
9 850 9
10 150 10
Table #settings:
userid active
------ ------
1 0
2 1
3 1
4 1
5 1
6 0
7 1
8 1
9 0
10 1
What I basically want to achieve is to select a specific row from #rank by ID, sort it by points and select 3 rows above the specific ID and 3 row below the specific ID but only for rows where the active column (from #settings) for the user equals 1.
For example:
I would like to select from #rank the ID of 8, and it should return me the following:
rank points userid
---- ----- ------
2 150 10
3 230 7
4 300 2
5 350 8
6 900 3
7 1500 4
I have created quite an extensive query for this, but the problem is, that it is ranking the columns before it decides that the user is active or not. However I need to rank the columns after it is decided that the user is active or not.
SELECT sub2.sort, sub2.points, sub2.userid
FROM
(
SELECT #sort1 := #sort1 + 1 AS sort, puu.points, puu.userid
FROM rank as puu,
(SELECT #sort1 := 0) s
LEFT JOIN
(
settings as p11
)
ON puu.userid = p11.userid,
WHERE p11.active = 1
ORDER BY puu.points DESC
) sub1
INNER JOIN
(
SELECT #sort2:=#sort2+1 AS sort, p2.points, p2.userid
FROM rank as p2,
(SELECT #sort2 := 0) s
LEFT JOIN
(
settings as p12
)
ON p2.userid = p12.userid,
WHERE p12.active = 1
ORDER BY points DESC
) sub2
ON sub1.userid = :userid
AND sub2.sort BETWEEN (sub1.sort - 5) AND (sub1.sort + 5)
Can you guys find any solution for my problem? If you can provide an SQLfiddle demo, that would be really awesome!
SELECT sort, points, user_id, active FROM (
SELECT #pos := #pos + 1 AS sort, id, points, r.user_id, s.active,
IF(user_id = :userid, #userpos := #pos, 0)
FROM rank r
JOIN settings s USING(user_id)
JOIN (SELECT #pos := 0, #userpos := 0) p
WHERE s.active = 1
ORDER BY points DESC
) list
WHERE sort BETWEEN #userpos - 3 AND #userpos + 3
I made a fiddle here: sqlfiddle
Possibly using 2 unioned queries to get the values before the ranking:-
SELECT #rank:=#rank+1 AS rank, points, userid
FROM
(
SELECT id, points, userid
FROM
(
SELECT rank.id, rank.points, rank.userid
FROM rank
INNER JOIN
(
SELECT points
FROM rank
WHERE id = 8
) sub0
ON rank.points >= sub0.points
INNER JOIN settings
ON rank.userid = settings.userid
WHERE settings.active = 1
ORDER BY rank.points LIMIT 3
) sub1
UNION ALL
SELECT id, points, userid
FROM
(
SELECT rank.id, rank.points, rank.userid
FROM rank
INNER JOIN
(
SELECT points
FROM rank
WHERE id = 8
) sub0
ON rank.points < sub0.points
INNER JOIN settings
ON rank.userid = settings.userid
WHERE settings.active = 1
ORDER BY rank.points DESC LIMIT 3
) sub1
) sub2
CROSS JOIN (SELECT #rank:=0) sub3
ORDER BY points