I have like this table at my mysql db for highscore.
and I got SQL for get rank of all users.
SELECT b.id
, b.name
, #rank_cnt := IF(#prev_score = b.score,#rank_cnt,#rank_cnt+1) AS rank
, #prev_score := b.score AS score
FROM BBR b
CROSS
JOIN ( SELECT #rank_cnt := 0, #prev_score := NULL) i
ORDER BY b.score DESC, b.id DESC
if I run above SQL, I get following result,
But I want to know from here, specific user's rank info only.
If I wrote WHERE name = 'sim' before ORDER BY, his rank become 1.
I expect here '4' as result.
How should I revise?
Thanks much.
SET #rank_cnt := 0;
SET #prev_score := NULL;
SELECT * FROM (
SELECT b.id
, b.name
, #rank_cnt := IF(#prev_score = b.score,#rank_cnt,#rank_cnt+1) AS rank
, #prev_score := b.score AS score
FROM BBR b
ORDER BY b.score DESC, b.id DESC
) AS subQ
WHERE subQ.name = "sim";
If you are using the same connection, you shouldn't need that bogus "JOIN" to initialize your session variables.
You can try below query,
select name
,Find_in_set(score, (select group_concat(distinct score order by score desc) from BBR)) rank
from BBR
where name='sim';
Related
This question already has answers here:
Rank function in MySQL
(13 answers)
Closed 4 years ago.
SELECT u.user_id, u.user_uid, s.ostats, s.attack, s.defense
FROM stats s JOIN
users u
ON s.id = u.user_id
ORDER BY s.ostats DESC;
So in above data, "ostats"(overall) is just a sum of attack+defense and by using this query I could display users in descending order of their "ostats" values..
But how do I assign and display rank of each user, like the one with most "ostats" valued user as Rank 1 and the second highest "ostats" valued user as Rank 2 and so on..?
What about using a variable to keep track of the row number?
SET #rank = 0;
SELECT
u.user_id,
u.user_uid,
s.ostats,
s.attack,
s.defense,
(#rank:=#rank + 1) AS rank
FROM stats s
JOIN users u on s.id = u.user_id
ORDER BY s.ostats DESC;
You can assign a row number using variables:
SELECT u.user_id,u.user_uid, s.ostats, s.attack, s.defense,
s.ranking
FROM (SELECT s.*, (#rn := #rn + 1) as ranking
FROM (SELECT s.* FROM stats s ORDER BY s.ostats DESC) s CROSS JOIN
(SELECT #rn := 0) params
) s JOIN
users u
ON s.id = u.user_id
ORDER BY s.ostats DESC;
In the event of ties, this will give different users different rankings. If that is an issue, you can use this modified form:
SELECT u.user_id,u.user_uid, s.ostats, s.attack, s.defense,
s.ranking
FROM (SELECT s.*,
(#rn := if(#o = ostats, #rn,
if(#o := ostats, #rn + 1, #rn + 1)
)
) as ranking
FROM (SELECT s.* FROM stats s ORDER BY s.ostats DESC) s CROSS JOIN
(SELECT #rn := 0, #o := -1) params
) s JOIN
users u
ON s.id = u.user_id
ORDER BY s.ostats DESC;
Of course, in MySQL 8.0, you can use row_number(), rank() or dense_rank() for this purpose.
I Hope someone could help me.
My Query.
SELECT * FROM `tbl_device`
INNER JOIN `tbl_temperature` ON tbl_device.ID = tbl_temperature.DevID
Result.
How can get something like this as shown in the photo on the link.
I need to get only the last 3 result of the tbl_device.DevID
I apologize for my bad english, it's really hard to explain. Any help is realy much appreciated.
Thanks a lot!
It should be something like
SELECT * FROM `tbl_device`
INNER JOIN `tbl_temperature` ON tbl_device.ID = tbl_temperature.DevID
ORDER BY tbl_temperature.DevID DESC
LIMIT 3 OFFSET 0
The order column can be not the same as in my example. Google MySQL LIMIT OFFSET
Or if you need to get only three last results from one of your tables then join it to another then it will be something like
SELECT * FROM tbl_device INNER JOIN
(SELECT .... FROM other_table ORDER BY your_column DESC LIMIT 3 OFFSET 0) as
T1 ON T1.id = tbl_device.ID
The simplest way is to use ANSI-standard window functions (row_number() in particular). But MySQL does not support those (yet).
In MySQL, probably the best way is to use variables:
SELECT . . .
FROM tbl_device d JOIN
(SELECT t.*,
(#rn := if(#d = t.devid, #rn + 1,
if(#d := t.devid, 1, 1)
)
) as rn
FROM (SELECT t.*
FROM tbl_temperature t
ORDER BY DevID, id DESC
) t CROSS JOIN
(SELECT #d := -1, #rn := 0) params
) t
ON tbl_device.ID = tbl_temperature.DevID
WHERE rn <= 3;
EDIT:
Here is a simpler way to express the logic. It might be performant with the right indexes:
SELECT d.*, t.*
FROM tbl_device d INNER JOIN
tbl_temperature t
ON d.ID = t.DevID
WHERE t.ID >= (SELECT t2.ID
FROM tbl_temperature t2
WHERE t2.DevId = t.DevId
ORDER BY t2.ID DESC
OFFSET 2 LIMIT 1
);
For performance, this can use an index on tbl_temperature(devid, id).
This code create's rank on the fly and set's them accordingly.. Now the question is how do I update the Rank values in the table, without duplicating?I have posted this question recently but didn't find the solution.I am applying this code to a PHP code so that the rank updates with respect to TeamPoints ...
Help me Please! Thanks ...
SELECT TeamID,
TeamName,
TeamLeader,
TeamEmail,
TeamWins,
TeamLoss,
TeamPoints,
TeamRank
FROM
(
SELECT TeamID,
TeamName,
TeamLeader,
TeamEmail,
TeamWins,
TeamLoss,
TeamPoints,
#Rank := #Rank + 1 AS TeamRank
FROM team
CROSS JOIN (SELECT #Rank:=0) Sub0
ORDER BY TeamPoints DESC
) Sub1
You are just doing a SELECT statement. In order to UPDATE it really you have to use an UPDATE statement on the original table and use that query to feed values of teamRank:
UPDATE team t
INNER JOIN(
SELECT TeamID,
TeamPoints,
#Rank := #Rank + 1 AS TeamRank
FROM team
CROSS JOIN (SELECT #Rank:=0) Sub0
ORDER BY TeamPoints DESC
) a ON a.teamID = t.teamID
SET t.teamRank = a.teamRank
I need to place set #rank:=0; in this query, but where can i place it?
SELECT #rank:=#rank+1 AS rank, p.* FROM points p
inner join distributor d
on p.distributor_id=d.id_distributor
where p.month='$prev_month'
and d.group='$dist_group'
ORDER BY p.tot_point DESC
i have to use mysql_query("set #rank:=0;"); before the main query, it's works. but in another server it won't work.
any ideas ?
SELECT #rank:=#rank+1 AS rank, p.* FROM points p, (SELECT #rank:=0) AS dummy
inner join distributor d
on p.distributor_id=d.id_distributor
where p.month='$prev_month'
and d.group='$dist_group'
ORDER BY p.tot_point DESC
Basicly just add , (SELECT #rank:=0) AS dummy after FROM points p.
My prefered layout on this query:
SELECT #rank := #rank + 1 AS rank, p.*
FROM
points AS p
CROSS JOIN
(SELECT #rank:=0) AS dummy
INNER JOIN
distributor AS d
ON p.distributor_id = d.id_distributor
WHERE p.month = '$prev_month'
AND d.group='$dist_group'
ORDER BY p.tot_point DESC ;
I'm running a query daily to compile stats - but it seems really inefficient. This is the Query:
SELECT a.id, tstamp, label_id, (SELECT author_id FROM b WHERE b.tid = a.id ORDER BY b.tstamp DESC LIMIT 1) AS author_id
FROM a, b
WHERE (status = '2' OR status = '3')
AND category != 6
AND a.id = b.tid
AND (b.type = 'C' OR b.type = 'R')
AND a.tstamp1 BETWEEN {$timestamp_start} AND {$timestamp_end}
ORDER BY b.tstamp DESC
LIMIT 500
This query seems to run really slow. Apologies for the crap naming - I've been asked to not reveal the actual table names.
The reason there is a sub select is because the outer select gets one row from the table a and it gets a row from table b. But also need to know the latest author_id from table b as well, so I run a subselect to return that one. I don't want to run another select inside a php loop - as that is also inefficient.
It works correctly - I just need to find a much faster way of getting this data set.
If b.tstamp is unique within b.tid, take OMG Ponies' solution.
Otherwise you could try this solution. It sorts the whole result by b.tstamp DESC and adds a ranking per author_id. The outer selects takes only the row with rank = 1, which is the one with the greatest tstamp per author_id.
SELECT id, tstamp, label_id, author_id
FROM (SELECT id,
tstamp,
label_id,
author_id,
CASE
WHEN #author_id != author_id THEN #row_num := 1
ELSE #row_num := #row_num + 1
END AS rank,
#author_id := b.author_id
FROM a,
b,
(SELECT #row_num := 0, #author_id := NULL) y
WHERE a.id = b.tid
AND (status = '2' OR status = '3')
AND category != 6
AND (b.type = 'C' OR b.type = 'R')
AND a.tstamp1 BETWEEN {$timestamp_start} AND {$timestamp_end}
ORDER BY b.author_id, b.tstamp DESC
) x
WHERE x.rank = 1
LIMIT 500
I have not tried it, so please comment if it does not work.
Try:
SELECT a.id,
b.tstamp,
label_id,
y.author_id
FROM TABLE_A a
JOIN TABLE_B b ON b.tid = a.id
JOIN (SELECT b.tid,
MAX(b.tstamp) 'm_tstamp'
FROM TABLE_B b
GROUP BY b.tid) x ON x.tid = a.id
JOIN (SELECT b.tid,
b.author_id,
b.tstamp
FROM TABLE_B b
GROUP BY b.tid) y ON y.tid = a.id
AND y.tstamp = x.m_tstamp
WHERE status IN ('2', '3')
AND b.type IN ('C', 'R')
AND category != 6
AND a.tstamp1 BETWEEN {$timestamp_start} AND {$timestamp_end}
ORDER BY b.tstamp DESC
LIMIT 500