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.
Related
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
I am new to SQL.
I have written following query in MySQL
select * from msgs where (msgs.toid = 1 or msgs.fid = 1) group by fid,toid;
this query returns values as shown below.
|message_id | toid | fid |
68 4 1
70 1 9
72 1 4
78 5 1
80 9 1
My expected result should be
|message_id | toid | fid |
72 1 4
78 5 1
80 9 1
It mean I should not get repeated values(based on two columns values toid,fid) and it should be the highest id value.
The combination of toid and fid should be unique.
You can use greatest(),least() to check whether another row with the same combination of id's and a higher message id does not exist (which means the selected row has the highest message id for the given combination).
select * from msgs m where (toid = 1 or fid = 1)
and not exists (
select 1 from msgs m2
where greatest(m2.toid,m2.fid) = greatest(m.toid,m.fid)
and least(m2.toid,m2.fid) = least(m.toid,m.fid)
and m2.message_id > m.message_id
)
EDIT - another way using row_number()
select * from (
select * ,
row_number() over (partition by greatest(toid,fid),
least(toid,fid) order by message_id desc) rn
from msgs m where (toid = 1 or fid = 1)
) t1 where rn = 1
You can use this query:
SELECT
MAX(message_id) AS message_id,
LEAST(toid, fid) AS toid,
GREATEST(toid, fid) AS fid
FROM
msgs
GROUP BY
LEAST(toid, fid) AS toid,
GREATEST(toid, fid) AS fid
yes it will return for example
80 1 9
instead of
80 9 1
but since (1,9) is equivalent to (9, 1) it should not be a problem. If it is, see FuzzyTree's answer.
SELECT *
FROM msgs m
WHERE NOT EXISTS ( SELECT 'a'
FROM msgs m2
WHERE m2.msg_id > m.msg_id
AND (
( m.toid = m2.toid
AND m.fid = m2.fid
)
OR ( m.toid = m2.fid
AND m.fid = m2.toid
)
)
)
AND (m.toid = 1 OR m.fid = 1)
Return the last messages for conversation between two user
You could also try this.
select * from msgs m
where (toid = 1 or fid = 1)
and not exists ( select 1 from msgs m2
where (m2.toid + m2.fid) = (m.toid + m.fid)
and m2.message_id > m.message_id
)
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
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
Here's my mysql table:
Table League (userid and lid are primary keys):
*userid* *lid* rank win loss streak score
---------------------------------------------------------
2 1 1 2 0 2 10
2 3 2 1 1 1 5
5 1 2 1 1 1 5
I'm trying to select the users with the top score only once. For example since userid 2 is in league (lid) 1 and 3, only his top score will be selected in the query. So in that case the row with score 10 would be selected since that's the users top score from both league 1 and 3. The row with lid 3 will not be selected.
So the query results should look like this:
userid lid rank win loss streak score
---------------------------------------------------------
2 1 1 2 0 2 10
5 1 2 1 1 1 5
As you can see userid 2 with lid 3 was not in the result because the score 10 from lid 1 was grater than score 5 from league 3. Any ideas?
SELECT l.userid, u.username, l.lid, l.rank, l.win, l.loss, l.streak, l.score
FROM (SELECT userid, MAX(score) AS MaxScore
FROM League
GROUP BY userid) q
INNER JOIN League l
ON q.userid = l.userid
AND q.MaxScore = l.score
INNER JOIN users u
ON l.userid = u.userid
SELECT *
FROM table t1
WHERE t1.score = (SELECT MAX(t2.score)
FROM table t2
WHERE t1.userid = t2.userid)
This will display ties, don't know if you want those or not.
Here the simplest solution:
SELECT *
FROM League t1
WHERE
t1.lig = (SELECT t2.lig
FROM League t2
WHERE t2.userid = t1.userid
ORDER BY score desc
LIMIT 1
)