getting rank of a row in a rowset - mysql

I have the following rows :
id name score
1 Bill 0
2 Kim 8
3 Michael 30
4 Doug 22
5 Mellisa 1
When I do SELECT * FROM table ORDER BY score DESC, I get
id name score
4 Doug 22
3 Michael 30
2 Kim 8
5 Mellisa 1
1 Bill 0
Now I want to get only one row, so I'll add a where clause, but problem is the ranking.
I'm producing pseudo ranks in my php code, i.e. the first row in the rowset is assigned rank 1, second is assigned rank 2 and so on...
So when I do SELECT * FROM table WHERE id = 5, apparently all the rank information is lost. How to get over this problem? Is there any way I could get the position of the row in rowset before adding the where clause?

Wrap the query in a subquery so that the rank will be preserved. Here's an example,
-- the example produces rank based on highest score.
SELECT *
FROM
(
SELECT #rank := ifnull(#rank, 0) + 1 Rank,
Id, name, Score
FROM tableName a
ORDER BY Score DESC
) x
WHERE ID = 5
SQLFiddle Demo

SELECT id, name, score, FIND_IN_SET( score, (
SELECT GROUP_CONCAT( score
ORDER BY score DESC )
FROM ScoreDetail)
) AS rank
FROM ScoreDetail
Where id=5
This will solve your problem....

Related

Finding rows with latest date by id mysql

I have these 2 tables I am trying to write a query that will help me select all rows that gives this result
users
id
name
1
test
2
test2
logs
id
userId
message
date
1
1
this is a test
2020-10-07 12:57:14
2
1
another reason
2020-10-07 13:57:14
3
1
another reason 2
2020-10-07 14:57:14
4
2
another reason 3
2020-10-04 12:57:14
5
2
another reason 4
2020-10-05 12:57:14
6
2
another reason 4
2020-10-06 12:57:14
Output Table
I need to pass many user Ids like in this case (1,2) and get below table only return MAX (date) per row per userId
id
userId
message
date
3
1
another reason 2
2020-10-07 14:57:14
6
2
another reason 4
2020-10-06 12:57:14
Is this possible with one Query? This what I have but not working
SELECT
id ,
userId ,
message,
date
FROM logs
WHERE userId IN (1,2)
ORDER BY date DESC;
You may use the results of a window function ROW_NUMBER to retrieve these results.
SELECT
id,userId,message,date
FROM (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY userId
ORDER BY date DESC
) as rn
FROM
logs
) t
WHERE rn=1 AND
userId IN (1,2)
ORDER BY date DESC
and for older mysql versions
SELECT
id,userId,message,date
FROM (
SELECT
l.*,
#row_num:=IF(userId=#prev_user_id,#row_num+1,1) as rn,
#prev_user_id:=userId
FROM
logs l
CROSS JOIN (
SELECT #row_num:=0, #prev_user_id:=NULL
) as vars
ORDER BY userId, date DESC
) t
WHERE rn=1 AND
userId IN (1,2)
ORDER BY date DESC

MySQL add score column to SELECT high scores query

I have a database named users that contains the following:
userid name highscore
0 sam 20
1 james 39
2 jack 3
3 harry 46
Highscore table query
I am using a query found on this post to gather results for my high-score table:
SELECT s.*
FROM users AS s
JOIN
( SELECT DISTINCT highscore
FROM users
ORDER BY highscore DESC
LIMIT 3
) AS lim
ON s.highscore = lim.highscore
ORDER BY s.highscore DESC ;
This would return the top 3 results, i.e. the rows containing sam, james and harry.
Ranking query
I have a separate query for returning the rank of an individual user in the table:
SELECT 1 + COUNT(*) AS rank
FROM users
WHERE highscore > (SELECT highscore FROM users WHERE name = '$name');
Ranks are returned dynamically, rather than stored in a 'rank' column, because they constantly change depending on the highscores of other users.
Goal
I would like to merge the ranking query into the highscore table query, so that each row in the $result contains something along the lines of: ...,"rank":"(users rank)". Is this possible? Thanks.
if you want something like this
userid name highscore rank
3 harry 46 1
1 james 39 2
0 sam 20 3
you can use following query
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 ;

mysql ranking based on sum of values

having a mysql table with multiple records belonging many different users like this:
id score
1 , 50
1 , 75
1 , 40
1, 20
2 , 85
2 , 60
2 , 20
i need to get the rank of each id but after finding the sum of their score;
the rank should be the same if the total score for each player is the same.
this gives me the total for each player:
select id,sum(score) as total from table_scores group by id order by total desc;
is it posssible to find the sum like above and use it to rank the players in one query?
Something big missing from the accepted answer. The rank needs to be bumped after a tie. If you've got 2 tied for 3rd place, there is no 4th place.
The following query is an adjustment of the accepted SQL to account for this and reset the rank variable (#r in the query) to match the row value. You can avoid the extra addition in the CASE/WHEN but initializing #row to 1 instead of 0 but then the row value is off by 1 and my OCD won't let that stand even if row number is not valuable.
select
id, total,
CASE WHEN #l=total THEN #r ELSE #r:=#row + 1 END as rank,
#l:=total,
#row:=#row + 1
FROM (
select
id, sum(score) as total
from
table_scores
group by
id
order by
total desc
) totals, (SELECT #r:=0, #row:=0, #l:=NULL) rank;
You can rank rows using variables:
select
id, total,
CASE WHEN #l=total THEN #r ELSE #r:=#r+1 END as rank,
#l:=total
FROM (
select
id, sum(score) as total
from
table_scores
group by
id
order by
total desc
) totals, (SELECT #r:=0, #l:=NULL) rank;
Please see it working here.
i find one more way to this problem... This one is based on JOIN clause
SET #rank = 0;
SELECT t1.id, t1.score, t2.rank
FROM (SELECT id, SUM(score) as score
FROM table_scores GROUP BY id ORDER BY score Desc) AS t1
INNER JOIN
(SELECT x.score, #rank:=#rank + 1 as rank FROM
(SELECT DISTINCT(SUM(score)) AS score
FROM table_scores
GROUP BY id ORDER BY score DESC) AS x) AS t2
ON t1.score = t2.score
Here is SQL Fiddle: http://sqlfiddle.com/#!9/2dcfc/16
P.S. it's interesting to see there is more then one way to solve a problem...

Arrange data in specific order

I have a user table that contain 8 records. I want to arrange the data in descending order on the basis of field id (that is a primary key of that table) but except id 3 and 5. So eventually the result should be like
id name
-- ----
3 peter
5 david
8 john
7 stella
6 jim
4 jack
2 nancy
1 scott
Except id 3 and 5 rest of the data should be arranged in descending order and 3 and 5 should come in ascending order.
SELECT * FROM user ORDER BY IF(id=3 OR id=5, id, ~id) ASC
something like this:
order by
case
when id = 3 then 999
when id = 5 then 998
else id
end desc
This assumes that you really don't have more than 8 rows. Otherwise you must change the "magic" numbers that move 3 and 5 to the top.
I think the trick here is to use an enum.
SELECT id, name FROM my_table WHERE id IN (3, 5) ORDER BY ASC
UNION
SELECT id, name FROM my_table WHERE id NOT IN(3, 5) ORDER BY DESC
In MySQL, there is a function called FIELD which *returns zero if a value is not found on the list` eg,
SELECT *
FROM tableName
ORDER BY FIELD(id, 5, 3) DESC, id DESC
SQLFiddle Demo
FIELD

Order by top five repeated IDs

There is a table in my database duplicate_id which contains multiple ids and also contains many duplicate ids in it. What I have been trying to do is to sort top five ids which are being repeated the most in the table duplicate_id. Kindly let me know how can i do that
Table Structure: ID | Message
Expected output:
ID | Number of repeats
201 8
212 7
205 5
209 3
229 2
SELECT ID, COUNT(*) AS `Number of repeats`
FROM duplicate_id
GROUP BY ID
ORDER BY COUNT(*) DESC
LIMIT 5
Try the order by so sort your results:
Select * from table order by repeats desc limit 5
well... try this (I don't know mysql, so I have to guess)
select ID,
count(*) as 'Number of Repeats'
from duplicate_ID
group by ID
order by 2
Another approach would be
select ID, 'Number of Repeats'
from (
select ID,
count(*) as 'Number of Repeats'
from duplicate_ID
group by ID
) x
order by 'Number of Repeats'