MySQL-在选择时获取行号


181

如果项目已排序,是否可以运行select语句并获取行号?

我有一个这样的表:

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

然后,我可以运行此查询以按ID获取订单数量:

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

这样,我就可以itemID对表格中的每个表格进行计数:

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

我也想获得行号,所以我可以知道那itemID=388是第一行,234第二行,等等(本质上是订单的排名,而不仅仅是原始计数)。我知道我可以在返回结果集时用Java做到这一点,但是我想知道是否有一种方法可以纯粹在SQL中处理它。

更新资料

设置等级会将其添加到结果集中,但顺序不正确:

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)

1
供将来参考:如果要从1级到5级进行排序,请使用ORDER BY rank ASC(按升序顺序按等级排序)。我想这是您的意思,但顺序不正确
BlueCacti 2015年

Answers:


179

看看这个

将查询更改为:

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

最后选择是您的数量。


1
这会将排名添加到结果集中,但不会将它们排在正确的顺序中-更新了结果的问题
乔治

1
尝试保留ORDER BY ordercount DESC,然后将整个查询包装在另一个查询中SELECT,该查询从第一个查询中获取所有内容,但按等级列排序(在这种情况下为0)。
Mike Cialowicz

1
你能举个例子吗?我将如何包装选择?
乔治

9
看看swamibebop的答案
thaddeusmt 2011年

1
@MikeCialowicz,这不起作用。有关正确答案,请参阅我的解决方案或Swamibebop的解决方案。
Pacerier,2015年

178
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;

1
感谢您的澄清,这解决了我遇到的乱序问题。
thaddeusmt 2011年

1
谢谢,这对我真的很有用:)我很惊讶没有一种更直接的方法可以从结果集中获取行“索引”……但是无论如何,这很方便。
大鼠

您可以通过更改SELECT \ @rn:= \ @ rn + 1 AS排名,itemID,ordercount,\ @ tot:= \ @ tot + ordercount中的第一条select语句作为totalcount来添加具有递增总数的第四行。要定义\ @tot的初始值,应在t2之后添加:(SELECT \ @tot:= 0)t3。删除每个\ @之前的\,我必须使用它来规避mini-Markdown格式化。
Jan Ehrhardt 2014年

2
谁能解释的相关性t1t2
Jared 2014年

2
@ Jared,MySQL语法只需要一些内容即可。它可以是任何东西,甚至xy
Pacerier,2015年

31

Swamibebop的解决方案有效,但是通过利用table.*语法,我们可以避免重复内部的列名,select并获得更简单/更简短的结果:

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

这样就可以给您:

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;

您是否偶然知道@r := @r + 1在select语句中使用为什么起作用的原因,但是如果它在带有的存储过程中declare r int; set r = 0;,则会抱怨(on r := r +1)?
Dan M.

@Pacerier,第二个选择在某处是否保证行的顺序?我知道,没有顺序by子句的select返回的行的顺序在任何地方都不能保证,最外面的select就是这样,尽管它是从内部有序的select中选择的,所以可能是一个例外。但是,如果不是这样,我将看不到这是正确的解决方案,因为它与Chibu's Mike's具有相同的缺陷-无法保证选择的顺序会经过记录并编号。
Dan M.

您是否知道为什么只要不在字段列表中时ORDER BY都不起作用?看看我的结果:hastebin.com/aluqefunoy.rb

11

您可以使用MySQL变量来做到这一点。这样的事情应该起作用(尽管它包含两个查询)。

SELECT 0 INTO @x;

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

2
小心,这是行不通的,因为评估变量order by会发生这种情况。通过订购其他栏来尝试进行实验。同时尝试和。您会看到很多次它们都会失败,并且只有几次才能运行,这是纯粹的运气,这是由于原始“选择”的顺序与的顺序相同。请参阅我的解决方案和/或Swamibebop的解决方案。@xdescascorder by
Pacerier,2015年

@Pacerier您确定吗?我已经在另一个示例(基本上是从数字列中进行选择,然后根据其顺序对它们进行编号)中的类似查询感到疲倦,似乎如果我按var / row num进行了排序,那么当它更改了结果行的顺序时,但每个数字都有相同的行号。但是,如果按数字列排序,则ASC/ DESC会更改这些数字的编号顺序(从最小到最大,反之亦然)。因此,在这种情况下,似乎order by首先进行了评估。
Dan M.

1

现在它已内置在MySQL 8.0和MariaDB 10.2中:

SELECT
  itemID, COUNT(*) as ordercount,
  ROW_NUMBER OVER (PARTITION BY itemID ORDER BY rank DESC) as rank
FROM orders
GROUP BY itemID ORDER BY rank DESC
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.