mysql rank - row number where field is equal to X - mysql

This is my mysql DB:
id, auth, name, points
and what I want to get is to create a rank. So sort all the records by points, and get the number of the row where the auth field is equal to '1'
I were looking for this in stockoverflow archive, in google etc. However, I havn't find what I were looking for. I were trying to do it myself, but none of them didn't work for me.
Could anyone help me, please?

SELECT a.iterator, a.id, a.name, a.points
FROM (
SELECT #rank:=#rank+1 AS iterator, id, name, points, auth
FROM table, (SELECT #rank:=0) tmp
ORDER BY points DESC) a
WHERE a.auth = 1

This should give you the record with rank for the record with auth = 1:
SELECT * FROM
(
SELECT id, auth, name, points, #rownum := #rownum + 1 AS rank
FROM (
SELECT id, auth, name, points
FROM yourTable
ORDER BY points DESC
) a
JOIN (
SELECT #rownum := 0
) r
) b
WHERE b.auth = 1;
sqlfiddle demo

Related

Order by highest value alternating with lowest value

I currently need to order data by highest value down, and then lowest value up, in between.
My Query is close, but doesn't quite order by largest down, though it is inserting the lowest in between:
DEMO Fiddle
select users.*
from users CROSS JOIN (select #even := 0, #odd := 0) param
order by
IF(score > 1, 2*(#odd := #odd + 1), 2*(#even := #even + 1) + 1),
score DESC;
Current Results
Email Score
----- --------
foo1#gmail.com 42
foo5#gmail.com 1
foo2#gmail.com 49
foo6#gmail.com 0
foo3#gmail.com 37
foo4#gmail.com 7
foo#gmail.com 22
Desired Results
Email Score
----- --------
foo2#gmail.com 49
foo6#gmail.com 0
foo1#gmail.com 42
foo5#gmail.com 1
foo3#gmail.com 37
foo4#gmail.com 7
foo#gmail.com 22
You can achieve using MySQL but avoid such complex SQL statements as the same can be achieved using programming language very easily.
SET #totalRows := (CASE WHEN (SELECT COUNT(*) FROM users) IS NULL THEN 0 ELSE (SELECT COUNT(*) FROM users) END);
PREPARE stmt1 FROM '(SELECT t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY score DESC) AS row_num, email, score FROM users UNION ALL SELECT ROW_NUMBER() OVER (ORDER BY score ASC) AS row_num, email, score FROM users) AS t ORDER BY t.row_num, t.score DESC LIMIT 0,?)';
EXECUTE stmt1 USING #totalRows;
Here is the explanation to achieve it:
Set variable #totalRows contains total rows in users table as that many rows will be displayed as a final result set.
Used ROW_NUMBER() function of MySQL to set ordering based on SOCRE field DESCENDING and ASCENDING for another result set.
Combined both the result set using UNION ALL statement of MySQL
Add the LIMIT keyword to make sure the final result must have a total number of rows that should not exceed #totalRows variable.
As in MySQL LIMIT statement we can't pass a dynamic value at a query level. I used the approach of prepare a statement.
You can ignore row_num column I used as final result set.
Hope my solution will help you.
For MySql 8.0+ you can use ROW_NUMBER() window function:
SELECT email, score
FROM (
SELECT *,
ROW_NUMBER() OVER (ORDER BY score DESC) rn1,
ROW_NUMBER() OVER (ORDER BY score ASC) rn2
FROM users
) t
ORDER BY LEAST(rn1, rn2), rn1;
For previous versions you can simulate ROW_NUMBER() with correlated subqueries (with the cost of poor performance for large datasets):
SELECT email, score
FROM (
SELECT u1.*,
(SELECT COUNT(*) FROM users u2 WHERE u2.score > u1.score) rn1,
(SELECT COUNT(*) FROM users u2 WHERE u2.score < u1.score) rn2
FROM users u1
) t
ORDER BY LEAST(rn1, rn2), rn1;
See the demo.

Getting the user's position in the leaderboard

Query stopped working (getting the user's position in the leaderboard):
SELECT
`rank`, `uid`, `battleWinScore`
FROM
(SELECT
#rank:=#rank+1 AS `rank`, `uid`, `battleWinScore`
FROM
`rating`, (SELECT #rank := 0) r
ORDER BY `battleWinScore` DESC
) t
WHERE uid = 572;
In the rating table, we need to get the user's position by field battleWinScore.
I am absolutely not good at mysql. Help =)
If you are running MySQL 8.0, just use row_number() (or rank(), if you want to consistently allow ties).
select *
from (
select uid, battleWinScore, rank() over(order by battleWinScore desc) rn
from rating
) r
where uid = 572
In earlier versions, I would recommend a correlated subquery rather than user variables:
select uid, battleWinScore
(select count(*) + 1 from rating r1 where r1.battleWinScore > r.battleWinScore) as rn
from rating r
where uid = 572

MySQL rank query. Get the position of a specific member

I have the following table on my DataBase:
TimeRank(user-id, name, time)
I would like to order the table by time and get the position of an specific ID on the table, for example:
The user nÂș 68 is on the 3rd position.
I only need to do a query that returns the position of the user.
MySQL don't have the function row_number, so I don't know how to do it.
SELECT x.user-id,
x.name,
x.time,
x.position
FROM (SELECT t.user-id,
t.name,
t.time,
#rownum := #rownum + 1 AS position
FROM TABLE TimeRank t
JOIN (SELECT #rownum := 0) r
ORDER BY t.time) x
WHERE x.user-id = 123
Alternative:
SELECT user-id,
(SELECT COUNT(*) FROM TimeRank WHERE time <= (SELECT time FROM TimeRank WHERE user-id = 123)) AS position,
time,
name
FROM TimeRank
WHERE user-id = 123
You can generate a position column with a variable
set #pos=0;
select pos,user_id
from (select #pos:=#pos+1 pos,user_id from TimeRank order by time) s
where user_id=68;
If indexing is a concern, you can add a column to your table and update it with
set #pos=0;
update TimeRank set position=(#pos:=#pos+1) order by time;

Sql - count the number of occurence for each duplicate value

Edit: What I want is to rank the frequency of all duplicates. I tried to use the code suggested earlier:
SELECT
t.*,
#rn:=IF(#name = name,
#rn + 1,
IF(#name:=name, 1, 1)) freq
FROM
(SELECT
*
FROM
student
ORDER BY name) t
CROSS JOIN
(SELECT #name:=NULL, #rn:=0) t2;
This, however, were able to count the frequency but only if they are consecutively ordered. See image below:
Instead of being counted as 3, number 1 under id 6 was counted back to 1.
It seems like you need every occurrence of the name, so a simple group won't do. Try something like this:
SELECT s.name AS "Name of Student",
(SELECT COUNT(name) FROM student ss WHERE s.name = ss.name) AS "Frequency of Late"
FROM student s
SELECT
name, COUNT(*)
FROM
TableName
GROUP BY
name
This query should work for you.
Use user variables for this:
SELECT
t.*,
#rn:=IF(#name = name,
#rn + 1,
IF(#name:=name, 1, 1)) freq
FROM
(SELECT
*
FROM
student
ORDER BY name) t
CROSS JOIN
(SELECT #name:=NULL, #rn:=0) t2;
EDIT:
If you want to order by date and freq later, you can do:
select * from (
/* the above query */
) t order by the_date_column desc, freq;
EDIT 2:
For the updated question, see below:
SELECT
*
FROM
(SELECT
t.*,
#rn:=IF(#number = number, #rn + 1, IF(#number:=number, 1, 1)) freq
FROM
(SELECT
*
FROM
your_table
ORDER BY number) t
CROSS JOIN (SELECT #number:=NULL, #rn:=0) t2) t
ORDER BY id;
DEMO # SQLFiddle
This is your solution
SELECT
Student_Name AS StudentName,count(Student_Name) Total
FROM
Student_Table
GROUP BY
Student_Name`

Rank in MySQL table

I have a MySQL table called "MyTable" and it basically lists usernames and points (two columns, name and points). I want to say something like "what is joe1928's rank?", which of course is based off his points. How could I do this in MySQL without having to download all that data and sort it and determine the rank myself?
The person with the highest number of points would be ranked 1.
Try getting the number of people with a higher score than your user:
select count(*) from MyTable where score > (select score from MyTable where user = 'Joe');
That will return 0 for the top user.
This page seems to describe and solve your problem.
Notes from that page:
SET #rownum := 0;
SELECT rank, correct FROM (
SELECT #rownum := #rownum + 1 AS rank, correct, uid
FROM quiz_user ORDER BY correct DESC
) as result WHERE uid=xxxxxxxx
SELECT #r AS Rank
FROM MyTable u, (SELECT #r := 0)
WHERE (#r := #r + 1) * (u.Username = 'joe1928')
ORDER BY u.Score DESC
LIMIT 1
select * from [TABLENAME] where [USERNAME] = blah order by [POINTS] desc limit 1;
Based on the link posted by #Dave your query will look like something below:
select Rank,name from
(select #rownum:=#rownum+1 AS 'Rank', p.name
from calls p, (select #rownum:=0) r
order by p.points desc) as rankResults
where name = 'joe';
This is from another stack overflow page, seems to solve your problem.
SELECT uo.*,
(
SELECT COUNT(*)
FROM users ui
WHERE (ui.points, ui.id) >= (uo.points, uo.id)
) AS rank
FROM users uo
WHERE id = #id