Right now I have this:
SELECT
#rownum := #rownum + 1 AS rownum,
T1.*
FROM
(
SELECT user.username, points
FROM scores
JOIN users AS user ON user.id = scores.user_id
) AS T1, (SELECT #rownum := 0) AS r
ORDER BY T1.points DESC, rownum ASC
And this returns usernames, points and row number. Points are ordered but row numbers are all messed up. If I put ORDER BY into the nested select then row nubmers are ordered but points are not. So what I need to change so that I get points ordered in descending order and row number would be in ascending, what I wanna create is leaderboards, so that user whit most point is first etc.
It looks like you need your rownum to be paired up with points that have been pre-ordered. Hence you need to move ORDER BY on points into the nested select:
SELECT
#rownum := #rownum + 1 AS rownum,
T1.*
FROM
(
SELECT user.username, points
FROM scores
JOIN users AS user ON user.id = scores.user_id
ORDER BY points DESC
) AS T1, (SELECT #rownum := 0) AS r
ORDER BY rownum ASC
Does this do what you want?
SELECT (#rownum := #rownum + 1) AS rownum,
us.*
FROM (SELECT u.username, s.points
FROM scores s JOIN
users u
ON u.id = s.user_id
ORDER BY s.points DESC
) us CROSS JOIN
(SELECT #rownum := 0) params;
Basically, this just leaves the ordering in the subquery.
If points is not a number, then use ORDER BY (s.points + 0) DESC in the subquery. Or fix the data so it is stored as a number.
Related
I want to rank the total stats of a group of users and assign a rank variable to them.
I used this thread for the Rank variable.
This is my Query atm:
SELECT #rank := #rank + 1 AS rank
, SUM(stats.points) AS x
FROM
( SELECT #rank := 0 ) r
, groups
LEFT
JOIN user_group
ON groups.id = user_groups.clan
LEFT
JOIN stats
ON user_groups.user = stats.id
GROUP
BY groups.id
ORDER
BY x DESC
RANK | points
--------------
47 | 3400
1 | 2500
75 | 1200
As you can see the Sorting by Points works fine, but the Rank variable seems to just pick random values.
Can anyone find a way to assign the rank correctly?
Use a subquery for the aggregation and ordering:
SELECT id, sum_points, #rank := #rank + 1 AS rank
FROM (SELECT g.id, SUM(s.points) AS sum_points
FROM groups g LEFT JOIN
user_group ug
ON g.id = ug.clan LEFT JOIN
stats s
ON ug.user = s.id
GROUP BY g.id
ORDER BY sum_points DESC
) s CROSS JOIN
(SELECT #rank := 0) params;
This has been an issue in MySQL for a while -- variables don't work well with aggregation and ordering.
Note that in MySQL 8+, this is much more simply written as:
SELECT g.id, SUM(s.points) AS sum_points,
ROW_NUMBER() OVER (ORDER BY SUM(s.points) DESC) as rank
FROM groups g LEFT JOIN
user_group ug
ON g.id = ug.clan LEFT JOIN
stats s
ON ug.user = s.id
GROUP BY g.id
I'm trying to follow this example: MySQL - ranking by count() and GROUP BY but my rank column keeps returning nil.
Here's my query:
SELECT
#rownum := #rownum+1 AS rank,
q.id,
q.Name,
q.count
FROM
(SELECT
Accounts.id,
Accounts.Name,
COUNT(Accounts.Name) AS count
FROM
player_to_team_histories
INNER JOIN
team_histories ON team_histories.id = player_to_team_histories.team_history_id
INNER JOIN
teams ON teams.id = team_histories.team_id
INNER JOIN
accounts ON accounts.id = teams.account_id
WHERE
accounts.AccountTypeId = 1 AND player_id IN (SELECT
player_id
FROM
player_to_team_histories
WHERE
player_to_team_histories.not_valid IS NULL AND team_history_id = (SELECT
team_history_id
FROM
player_to_team_histories
INNER JOIN
team_histories ON team_histories.id = player_to_team_histories.team_history_id
WHERE
player_to_team_histories.id = 574651))
GROUP BY Accounts.Name
ORDER BY count DESC)q
Every column except rank is returning as expected, and rank is returning null for every row.
You have to initialize your rownum to 0 before starting to increment it, either by
SET #rownum := 0;
before the query, or by a separate SELECT clause after your first FROM:
SELECT ...
FROM
(SELECT #rownum := 0 ) counter,
(SELECT
... )
I'm using this query:
SELECT A.place_idx,A.place_id,B.TOTAL_CNT,(#r := #r + 1) AS rank FROM CUSTOM_LIST
AS A
INNER JOIN
(SELECT #r := 0)
AS C
INNER JOIN
(SELECT place_id,COUNT(place_id) AS TOTAL_CNT from COUNT_TABLE GROUP BY place_id)
AS B ON B.place_id=A.place_id order by B.TOTAL_CNT desc;
Which gives this result:
But I want this result:
How do I need to modify my query? What am I doing wrong?
SELECT *,(#r := #r + 1) AS rank FROM
(
SELECT A.place_idx,A.place_id,B.TOTAL_CNT FROM CUSTOM_LIST
AS A
INNER JOIN
(SELECT place_id,COUNT(place_id) AS TOTAL_CNT from COUNT_TABLE GROUP BY place_id)
AS B ON B.place_id=A.place_id order by B.TOTAL_CNT desc
) AS T, (SELECT #r := 0) AS tt
Your C.rank is getting calculated as they are processed, not after they are sorted. There is really no need for this data, anyways. Since you're sorting the rows by your metric, you know the first row is the first rank, etc. You can handle it on the programming side of things after you pull it out.
Alternatively, you can put what you have in an inner select, then do the rank after.
In the above table, c position is 3.
Is there any function to find the position in Mysql?
update
try
select #rownum:=#rownum+1 ‘theposition’, t.* from mytable t, (SELECT #rownum:=0) r order by t.USER desc;
Use this:
SELECT x.user,
x.position,
x.number
FROM (SELECT t.user,
t.number,
#rownum := #rownum + 1 AS position
FROM TABLE t
JOIN (SELECT #rownum := 0) r
ORDER BY t.number DESC) x
WHERE x.user = 'c'
You can then get his position from x.position
I recommend you to add an id field. i don't know of any function to do that. you can select * and then in a script language search it or use a subquery. but i don't recommend that.
SELECT
#rowNumber := #rowNumber + 1 'RowNumber',
u.*
FROM Users u,
(SELECT #rowNumber := 0) r
ORDER BY u.User ASC
I have a table of items. item has id, score 1, score 2.
I want to select 12 known items (using WHERE id IN (....)) and order them by a score that is the sum of score1 and score2's ranks. rank is the location of the score if the 12 items were ordered by it.
How can I do this in mysql?
Edit:
After 4 answers I see that the solution is probably more complicated than I expected. so let me ask the question in another way.
If I use select *, [calculation] from table where id IN (odered list of ids). Can I somehow use the position of each id in the original ordered list of ids in [calculation]?
Out of my head:
CREATE TEMPORARY TABLE t_1(score_1_rank INT AUTO_INCREMENT, id)
CREATE TEMPORARY TABLE t_2(score_2_rank INT AUTO_INCREMENT, id)
INSERT INTO t_1(id)
SELECT id
FROM items i
WHERE id IN ()
ORDER BY score_1
INSERT INTO t_2(id)
SELECT id
FROM items i
WHERE id IN ()
ORDER BY score_2
SELECT ...
FROM items i
INNER JOIN t_1 t1
ON t1.id = i.id
INNER JOIN t_2 t2
ON t2.id = i.id
ORDER BY t1.rank + t2.rank
Did I understand your request correctly?
Is this what you are looking to do?
SELECT
(CAST(score1 AS INT) + CAST(score2 AS INT)) AS rank
FROM items
WHERE id IN(...)
ORDER BY rank DESC
SELECT id, score1, score2,
r1.rank AS rank1,
r2.rank AS rank2,
(r1.rank + r2.rank) rankSum
FROM items i
INNER JOIN (
SELECT #rank := #rank + 1 AS rank, id
FROM items, (SELECT #rank :=0) AS r
ORDER BY score1
) AS r1 ON r1.id = i.id
INNER JOIN (
SELECT #rank := #rank + 1 AS rank, id
FROM items, (SELECT #rank :=0) AS r
ORDER BY score2
) AS r2 ON r2.id = i.id
ORDER BY rankSum
But I doubt that this will be somehow very efficient, not only because the query cannot make use of the query cache.