【问题标题】:MySQL - Get row number on selectMySQL - 在选择时获取行号
【发布时间】:2011-01-31 23:57:09
【问题描述】:

如果项目已排序,我可以运行 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 到排名 5,请使用 ORDER BY rank ASC(按排名按升序排列)。我想这就是你的意思 但没有正确排序
  • ROW_NUMBER() in MySQL的可能重复

标签: mysql sql row-number


【解决方案1】:

看看this

将您的查询更改为:

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

最后的选择是你的计数。

【讨论】:

  • 这会将排名添加到结果集中,但没有将它们按正确的顺序排列 - 使用结果更新问题
  • 尝试保留ORDER BY ordercount DESC,然后将整个查询包装在另一个SELECT 中,该SELECT 从第一个获取所有内容,但按排名列排序(在本例中为0)。
  • 你能举个例子吗?我将如何包装选择?
  • 查看 swamibebop 的回答
  • @MikeCialowicz,这个doesn't work。请参阅我的解决方案或 Swamibebop 的解决方案以获得正确答案。
【解决方案2】:
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;

【讨论】:

  • 感谢您的澄清,这解决了我遇到的乱序问题。
  • 谢谢,这对我来说真的很有用 :) 我很惊讶没有更直接的方法可以从结果集中获取行“索引”......但无论如何感谢这很方便。
  • 您可以通过更改 SELECT \@rn:=\@rn+1 AS rank, itemID, ordercount, \@tot:=\@ 中的第一个选择语句来添加具有增量总数的第四行tot+ordercount 作为总数。要定义 \@tot 的初始值,应在 t2 之后添加:(SELECT \@tot:=0) t3。删除每个 \@ 之前的 \,我不得不用它来规避 mini-Markdown 格式。
  • 谁能解释t1t2的相关性?
  • @Jared,MySQL 语法只是需要一些东西。它可以是任何东西,甚至是xy
【解决方案3】:

Swamibebop 的解决方案有效,但通过利用 table.* 语法,我们可以 avoid repeating 内部 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;

【讨论】:

  • 您是否知道为什么在 select 语句中使用 @r := @r + 1 有效,但如果它在带有 declare r int; set r = 0; 的存储过程中,它会抱怨(在 r := r +1 上)?
  • @Pacerier,第二个选择的行顺序是否也有保证?我知道没有 order by 子句的 select 返回的行的顺序在任何地方都不能保证,最外面的 select 就是这样,虽然它是从内部有序 select 中选择的,所以它可能是一个例外。但是,如果不是,我看不出这是一个正确的解决方案,因为它与 Chibu 的 Mike 存在相同的缺陷 - 无法保证 select 将按哪个顺序遍历记录并对它们进行编号。
  • 您知道为什么 ORDER BY 不在字段列表中时不起作用吗?查看我的结果:hastebin.com/aluqefunoy.rb
【解决方案4】:

您可以使用 MySQL 变量来执行此操作。像这样的东西应该可以工作(不过,它由两个查询组成)。

SELECT 0 INTO @x;

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

【讨论】:

  • 小心,这是行不通的,因为order by 发生在变量@x 被评估之后。尝试通过使用其他列进行排序来进行试验。同时尝试descasc。您会看到很多时候它们会失败,并且只有在它起作用时,这是 纯粹的运气,因为您的原始“选择”的顺序与 @987654326 的顺序相同@。请参阅我的解决方案和/或 Swamibebop 的解决方案。
  • @Pacerier 你确定吗?我已经厌倦了另一个示例中的类似查询(基本上是从数字列中选择,并根据它们的顺序对其进行编号)似乎如果我按 var/row num 排序,当它改变了结果行的顺序时,但每个数字都有相同的行号。但是如果我按数字列排序,那么ASC/DESC 会改变这些数字的编号顺序(从最小到最大,反之亦然)。所以在这种情况下,order by 似乎首先被评估。
【解决方案5】:

它现在内置在 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

【讨论】:

    猜你喜欢
    • 2012-07-25
    • 2022-11-29
    • 1970-01-01
    • 2015-05-20
    • 2012-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多