Basically I have a table named hiscores where I want to search a nickname of one user and get his current rank, since the rank rown doesn't exist because the ranks are organized by lvl DESC and then by Experience , so I want a sql query where I search the name of that
"player1" and it returs me rank 2. or input healdeal and get rank 1
Table = hiscores
id - nickname- lvl - experience
1 - healdeal - 99 - 1000
2 - philip - 98 - 595
3 - Player1 - 98 - 620
4 - Mindblow - 52 - 35
I have tried the following
SELECT (COUNT(*) + 1) AS rank FROM hiscores WHERE lvl >(SELECT lvl FROM hiscores WHERE nickname="player1")
Assuming this is MySQL, this will work:
select #rownum:=#rownum+1 Rank,
h.*
from hiscores h,
(SELECT #rownum:=0) r
order by level desc, experience desc
SQLFiddle
If this is MS SQL Server 2005 onwards, you can directly use window functions, like so:
select *, rank() over (order by level desc, experience desc) Rank
from hiscores
In either case, if you want to filter by the nickname, you can put the above expression into a subquery and filter that by the nickname i.e.
select * from
(<ranking expression from above>) rankedresults
where nickname = <input>
I see. You are trying to calculate the rank. I think this might do it:
select count(*) as rank
from hiscores hs cross join
(select hs.*
from hiscores
where nickname = 'player1'
) hs1
where hs.lvl > hs1.lvl or
hs.lvl = hs1.lvl and hs.experience >= hs1.experience;
Actually, if you have ties on both experience and lvl, then this might be a better rank:
select 1 + count(*) as rank
from hiscores hs cross join
(select hs.*
from hiscores
where nickname = 'player1'
) hs1
where hs.lvl > hs1.lvl or
hs.lvl = hs1.lvl and hs.experience > hs1.experience;
If you are using MSSQL 2005+. You can do this:
Test data:
DECLARE #tbl TABLE(id INT,nickname VARCHAR(100),lvl INT, experience INT)
INSERT INTO #tbl
VALUES
(1 ,'healdeal',99,1000),
(2 ,'philip',98,595),
(3 ,'Player1',98,620),
(4 ,'Mindblow',52,35)
Query
;WITH CTE
AS
(
SELECT
RANK() OVER(ORDER BY lvl DESC,experience DESC) AS rank,
tbl.*
FROM
#tbl AS tbl
)
SELECT
*
FROM
CTE
WHERE
CTE.nickname='Player1'
Output
2 3 Player1 98 620
Related
Lets say I have two subqueries in a UNION statement like so:
(
SELECT *
FROM users
ORDER BY registration_date
)
UNION ALL
(
SELECT *
FROM food
ORDER BY popularity
)
The output is the following:
Bob
Alice
Steve
Mark
...
Sandwich
Pizza
Burger
Fries
...
Is it possible to output them in an alternating fashion, such that the output is:
Bob
Sandwich
Alice
Pizza
Steve
Burger
Mark
Fries
...
Each query output is thousands of items.
You could use row_number() if you are running MySQL 8.0:
(select name, 1 src, row_number() over(order by registration_date) rn from users)
union all
(select name, 2, row_number() over(order by popularity) from food)
order by rn, src
In each unioned subquery, we use row_number() to rank the records, and add another column, called src to identify from which table the record comes from.
Then all that is left to do is order by the assigned row_number(), using the additional column to alternate the records.
Note that I modified your query to enumerate the columns being selected in the subqueries; select * is generally not a good practice, especially with union all, which requires both datasets to have the same number of columns (with equivalent datatypes).
Just in case you are not using MySQL 8+, you can still simulate ROW_NUMBER using a correlated count query:
(
SELECT 1 AS idx, name,
(SELECT COUNT(*) FROM users u2 WHERE u2.registration_date < u1.registration_date) rn
FROM users u1
)
UNION ALL
(
SELECT 2, name,
(SELECT COUNT(*) FROM food f2 WHERE f2.popularity < f1.popularity) rn
FROM food f1
)
ORDER BY
rn,
idx;
DECLARE #id INT;
SET #id :=0;
SELECT id,t.* FROM(
SELECT u.*,(#id:=#id+1) AS id
FROM users u
ORDER BY registration_date
)
UNION ALL
(
SELECT f.*,(#id:=#id+2) AS id
FROM food f
ORDER BY popularity
)t
ORDER BY id;
I have a MySQL query that selects the players with the top 3 highest scores in my users table, then creates an extra column where their rank is assigned:
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 ;
Current progress
So, if the table looked like this:
userid name highscore
0 sam 20
1 james 39
2 jack 10
3 harry 46
4 jennie 7
The result of the query would be this:
userid name highscore rank
3 harry 46 1
1 james 39 2
0 sam 20 3
Question
How could I alter this query so it also display's the user and their rank in the list of results? E.g. if $userName = "jenny", how could I return:
userid name highscore rank
3 harry 46 1
1 james 39 2
0 sam 20 3
4 jenny 7 5 <-- Add this row and skip jack
Edit: I should mention - I am using MySQL version 5.0.96
For versions prior to 8.0...
SELECT *
FROM
( SELECT a.*
, #i := #i+1 i
FROM my_table a
JOIN (SELECT #i:=0) vars
ORDER
BY highscore DESC
, userid
) x
WHERE name = 'jennie'
OR i <= 3
ORDER
BY i;
https://www.db-fiddle.com/f/hYsiCE1bXeTnR2HzoJkKiR/0
If using MySQL 8+, then the RANK analytic function makes this easy:
WITH cte AS (
SELECT *, RANK() OVER (ORDER BY highscore DESC) rnk
FROM users
)
SELECT userid, name, highscore, rnk
FROM cte
WHERE rnk <= 3;
Try this,
select * from (
(select t1.userid,t1.name,t1.highscore,#rank1:=#rank1+1 'rank'
from (SELECT userid, name, highscore FROM users order by highscore desc) t1
join (select #rank1:=0) r
limit 3)
union
(select t2.userid,t2.name,t2.highscore,t2.rank from (select t1.userid,t1.name,t1.highscore,#rank2:=#rank2+1 'rank'
from (SELECT userid, name, highscore FROM users order by highscore desc) t1
join (select #rank2:=0) r) t2
where t2.name='jennie')) t;
The following query orders votes based on how many times users voted... I would like to know the # in the queue of the specific user.
SELECT #s:=#s+1 serial_number, user_id, COUNT(slug_owner) as cnt
FROM `votes_queue`,(SELECT #s:= 0) AS s
GROUP BY slug_owner
ORDER BY cnt DESC
serial_number | user_id | cntÂ
3 | 19 | 8
2 | 14 | 4
1 | 13 | 2
Essentially i need the numbers in the serial_number column to be reversed so I can tell that user 13 is #3 based on votes ..
Assign the serial numbers after generating the ordered count:
SELECT #s:=#s+1 serial_number, temp.*
FROM (
SELECT user_id, COUNT(slug_owner) as cnt
FROM `votes_queue`,
GROUP BY slug_owner
ORDER BY cnt DESC
) temp, (SELECT #s:= 0) AS s
The serial numbers are not reversed because GROUP BY and variables don't mix. An ORDER BY is fine. You can use #hjpotter92's solution, but the following also fixes the problem:
SELECT (#rn := #rn + 1) as serial_number, t.*
FROM (SELECT serial_number, user_id, COUNT(slug_owner) as cnt
FROM `votes_queue`
GROUP BY slug_owner
) t CROSS JOIN
(SELECT #rn := 0) params
ORDER BY cnt DESC;
I think the performance is the same. I am offering this answer just to clarify what the actual problem is.
I have a question about the query originally from http://jimmod.com/blog/2008/09/displaying-row-number-rownum-in-mysql/
SELECT IF(#points=p.points, #rownum, #rownum:=#rownum+1) rank,
p.*, (#points:=p.points) dummy
FROM `ranking` p, (SELECT #rownum:=0) x, (SELECT #points:=0) y
ORDER BY `points` DESC
Result of the query is:
rank user_id name score
-----------------------
1 4 Barney 100
2 2 Ted 88
3 1 Marshall 76
3 3 Robin 76
4 5 Lily 68
How can I get the same rank result based on user id?
Query below is based on user id, but the rank of Robin will be 4, not 3 like it should be.
SELECT rank FROM (SELECT #rownum:=#rownum+1 rank, p.*
FROM `ranking` p, (SELECT #rownum:=0) r
ORDER BY `points` DESC) a WHERE a.user_id = 3
Without testing it, seems like this should work using a subquery:
SELECT rank
FROM (
SELECT IF(#points=p.points, #rownum, #rownum:=#rownum+1) rank,
p.*, (#points:=p.points) dummy
FROM `ranking` p, (SELECT #rownum:=0) x, (SELECT #points:=0) y
ORDER BY `points` DESC
) t
WHERE user_id = 3
Your query above displays 4 because you're not using RANK, but rather just ROW NUMBER, and Robin shows up after Marshall (even though they have the same score).
Good luck.
I have a table user
Name | Poin
==================
user1 | 20
user2 | 30
user3 | 80
user4 | 60
user5 | 10
user6 | 85
And I have SQL query
SELECT *
FROM user
ORDER BY poin
It would appear that the data sequence based on points.
But what I need is data like this (for example, I was user1):
Position 1 : user6 - 85 point
Position 2 : user3 - 80 point
Position 3 : user4 - 60 point
You are position 5 : user1 - 20 point
UPDATE
I use this sql
SELECT x.name,
x.position
FROM (SELECT t.user,
#rownum := #rownum + 1 AS position
FROM user t
JOIN (SELECT #rownum := 0) r
ORDER BY t.poin DESC) x
WHERE x.user = 'user1'
This will give current rank for user1:
SELECT count(*) AS rank
FROM user
WHERE poin >= (SELECT poin FROM user WHERE name = 'user1')
Small issue with this query is that if another user has the same points, it will be assigned the same rank - whether it is correct, it is questionable.
If you want to simply add rank for every user, use this:
SELECT
#rank:=#rank+1 AS rank,
name,
poin
FROM user,
(SELECT #rank:=0) r
ORDER BY poin DESC
You can use small variation of this query to get rank of single user, but avoid issue of the same ranking ambiguity:
SELECT *
FROM (
SELECT
#rank:=#rank+1 AS rank,
name,
poin
FROM user,
(SELECT #rank:=0) r
ORDER BY poin DESC
) x
WHERE name = 'user1'
select * from user order by poin desc
Hope this helps
SELECT * FROM user ORDER BY poin DESC
The ORDER BY keyword is used to sort the result-set by a specified column.
The ORDER BY keyword sorts the records in ascending order by default.
If you want to sort the records in a descending order, you can use the DESC keyword.
SQL ORDER BY Syntax
SELECT column_name(s)
FROM table_name
ORDER BY column_name(s) ASC|DESC
SELECT Name,
Poin,
#rowNum := #rowNum + 1 AS position
FROM user
JOIN (SELECT #rowNum := 0) r
ORDER BY poin;
The following code:
SELECT count(*) AS rank
FROM user
WHERE poin >= (SELECT poin FROM user WHERE name = 'user1')
Has a problem when is has double point in different rows.
SELECT Name,
Poin,
#rowNum := #rowNum + 1 AS position
FROM user
JOIN (SELECT #rowNum := 0) r
ORDER BY poin DESC;