MySQL - Get row number on select


MySQL - Get row number on select



Can I run a select statement and get the row number if the items are sorted?



I have a table like this:


mysql> describe orders;
+-------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------+----------------+
| orderID | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| itemID | bigint(20) unsigned | NO | | NULL | |
+-------------+---------------------+------+-----+---------+----------------+



I can then run this query to get the number of orders by ID:


SELECT itemID, COUNT(*) as ordercount
FROM orders
GROUP BY itemID ORDER BY ordercount DESC;



This gives me a count of each itemID in the table like this:


itemID


+--------+------------+
| itemID | ordercount |
+--------+------------+
| 388 | 3 |
| 234 | 2 |
| 3432 | 1 |
| 693 | 1 |
| 3459 | 1 |
+--------+------------+



I want to get the row number as well, so I could tell that itemID=388 is the first row, 234 is second, etc (essentially the ranking of the orders, not just a raw count). I know I can do this in Java when I get the result set back, but I was wondering if there was a way to handle it purely in SQL.


itemID=388


234



Update



Setting the rank adds it to the result set, but not properly ordered:


mysql> SET @rank=0;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @rank:=@rank+1 AS rank, itemID, COUNT(*) as ordercount
-> FROM orders
-> GROUP BY itemID ORDER BY rank DESC;
+------+--------+------------+
| rank | itemID | ordercount |
+------+--------+------------+
| 5 | 3459 | 1 |
| 4 | 234 | 2 |
| 3 | 693 | 1 |
| 2 | 3432 | 1 |
| 1 | 388 | 3 |
+------+--------+------------+
5 rows in set (0.00 sec)





For future reference: If you want to order from rank 1 to rank 5, use ORDER BY rank ASC (ordering by rank in ASCending order). I guess that is what you mean by but not properly ordered
– GroundZero
Jan 9 '15 at 12:57


ORDER BY rank ASC





Possible duplicate of ROW_NUMBER() in MySQL
– Ciro Santilli 新疆改造中心 六四事件 法轮功
May 25 '16 at 14:13




4 Answers
4



Take a look at this.



Change your query to:


SET @rank=0;
SELECT @rank:=@rank+1 AS rank, itemID, COUNT(*) as ordercount
FROM orders
GROUP BY itemID
ORDER BY ordercount DESC;





That adds the rank to the result set, but doesn't put them in the proper order - updated question with results
– George
Mar 26 '10 at 0:22





Try keeping the ORDER BY ordercount DESC, and then wrap the whole query in another SELECT which gets everything from the first one, but orders by the rank column (0 in this case).
– Mike Cialowicz
Mar 26 '10 at 0:27


ORDER BY ordercount DESC


SELECT





Can you show an example of this? How would I wrap the selects?
– George
Mar 27 '10 at 18:21





Check out swamibebop's answer
– thaddeusmt
Mar 29 '11 at 1:22





@MikeCialowicz, This doesn't work. Refer to my solution or Swamibebop's solution for the right answer.
– Pacerier
Apr 24 '15 at 11:45



SELECT @rn:=@rn+1 AS rank, itemID, ordercount
FROM (
SELECT itemID, COUNT(*) AS ordercount
FROM orders
GROUP BY itemID
ORDER BY ordercount DESC
) t1, (SELECT @rn:=0) t2;





Thank for clarifying, this solved the out-of-order problem I was having.
– thaddeusmt
Mar 29 '11 at 18:49





Thanks, this was really useful for me :) I'm surprised there isn't a more straightforward way of getting row 'indexes' from a result set ... but anyway thanks this was handy.
– rat
Jan 5 '12 at 17:22





You can add a fourth row with an incremental totalcount by changing the first select statement in SELECT @rn:=@rn+1 AS rank, itemID, ordercount, @tot:=@tot+ordercount as totalcount. To define the initial value of @tot this should be added after the t2: (SELECT @tot:=0) t3. Delete the before every @, which I had to use to circumvent mini-Markdown formatting.
– Jan Ehrhardt
Apr 26 '14 at 0:22






Can anyone explain the relevance of t1 and t2?
– Jared
Apr 30 '14 at 3:11


t1


t2





@Jared, MySQL syntax just needs something to be there. It can be anything, even x and y.
– Pacerier
Apr 24 '15 at 11:10


x


y



Swamibebop's solution works, but by taking advantage of table.* syntax, we can avoid repeating the column names of the inner select and get a simpler/shorter result:


table.*


select


SELECT @r := @r+1 ,
z.*
FROM(/* your original select statement goes in here */)z,
(SELECT @r:=0)y;



So that will give you:


SELECT @r := @r+1 ,
z.*
FROM(
SELECT itemID,
count(*) AS ordercount
FROM orders
GROUP BY itemID
ORDER BY ordercount DESC
)z,
(SELECT @r:=0)y;





This worked like a champ for what I was needing. Thank you!
– user2020930
Mar 5 '16 at 14:31





Thank you! run it pretty well! thanks!
– Eric_Guo
Mar 16 '16 at 7:42





Do you by chance know why using @r := @r + 1 in a select statement works, but if it's in a stored procedure with declare r int; set r = 0;, it complains (on r := r +1)?
– Dan M.
Dec 17 '16 at 17:03


@r := @r + 1


declare r int; set r = 0;


r := r +1





@Pacerier, also is the order of rows the second select guaranteed somewhere? I know that the order of rows returned by the select without order by clause is not guaranteed anywhere, and the outermost select is exactly that, though it select from the inner ordered select, so it might be an exception. If it's not, however, I cannot see how this is a correct solutions since it'll have the same flaw as Chibu's Mike's - no guarantee in which order select will go through records and number them.
– Dan M.
Dec 17 '16 at 17:17





Works! This needs more votes!
– ZygD
Mar 12 '17 at 16:49



You can use MySQL variables to do it. Something like this should work (though, it consists of two queries).


SELECT 0 INTO @x;

SELECT itemID,
COUNT(*) AS ordercount,
(@x:=@x+1) AS rownumber
FROM orders
GROUP BY itemID
ORDER BY ordercount DESC;





Careful, this wouldn't work because order by happens after the variable @x has been evaluated. Try experimenting by ordering using the other columns. Also experiment with both desc and asc. You'll see that many times they'll fail and the only times when it works, it's by pure luck due to the order of your original "select" having the same order as the order of order by. See my solution and/or Swamibebop's solution.
– Pacerier
Apr 24 '15 at 11:43


order by


@x


desc


asc


order by





@Pacerier are you sure about that? I've tired similar query in a different example (basically select from the column of numbers, and number them according to their order) at it seemed that if I ordered by var/row num, when it changed the order of the resulting rows, but each number had the same row num. But if I order by the number column, then the ASC/DESC would change the order in which those numbers were numbered (from smallest to biggest or vice versa). So it looks like in that case order by was evaluated first.
– Dan M.
Dec 17 '16 at 17:42


ASC


DESC


order by




Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).


Would you like to answer one of these unanswered questions instead?

Popular posts from this blog

How to add background colour in existing image using Swift?

Moria Casán

How to make file upload 'Required' in Contact Form 7?