【问题标题】:MySQL get row position in ORDER BYMySQL在ORDER BY中获取行位置
【发布时间】:2011-04-06 14:13:24
【问题描述】:

使用以下 MySQL 表:

+-----------------------------+
+ id INT UNSIGNED             +
+ name VARCHAR(100)           +
+-----------------------------+

当按name ASC 排序时,如何选择单个 行及其在表中其他行中的位置。所以如果表数据是这样的,按名称排序时:

+-----------------------------+
+ id | name                   +
+-----------------------------+
+  5 | Alpha                  +
+  7 | Beta                   +
+  3 | Delta                  +
+ .....                       +
+  1 | Zed                    +
+-----------------------------+

如何选择Beta 行以获得该行的当前位置?我正在寻找的结果集是这样的:

+-----------------------------+
+ id | position | name        +
+-----------------------------+
+  7 |        2 | Beta        +
+-----------------------------+

我可以做一个简单的SELECT * FROM tbl ORDER BY name ASC 然后枚举 PHP 中的行,但是只为一行加载一个可能很大的结果集似乎很浪费。

【问题讨论】:

标签: sql mysql analytic-functions


【解决方案1】:

这是我能想到的唯一方法:

SELECT `id`,
       (SELECT COUNT(*) FROM `table` WHERE `name` <= 'Beta') AS `position`,
       `name`
FROM `table`
WHERE `name` = 'Beta'

【讨论】:

  • +1 不错的技巧...但是您可能想改用name &lt;= 'Beta'
  • 这种方法将为关系提供相同的position 值。
  • (删除了我之前的评论-我错了)...如果您在其中添加LIMIT 1 会怎样?在平局的情况下,您只会得到一排平局的最后位置。
  • 如果 OP 可以保证 name 字段是唯一的 - 那么没有理由使查询更复杂。如果他不能 - 那么让我们等待他对平局名称的预期结果。
【解决方案2】:

可能你需要的是添加语法

LIMIT

所以用

SELECT * FROM tbl ORDER BY name ASC LIMIT 1

如果你只需要一排..

【讨论】:

  • 这个答案不能解决这里的问题。你可以考虑删除它
【解决方案3】:

使用这个:

SELECT x.id, 
       x.position,
       x.name
  FROM (SELECT t.id,
               t.name,
               @rownum := @rownum + 1 AS position
          FROM TABLE t
          JOIN (SELECT @rownum := 0) r
      ORDER BY t.name) x
 WHERE x.name = 'Beta'

...获取唯一的位置值。这个:

SELECT t.id,
       (SELECT COUNT(*)
          FROM TABLE x
         WHERE x.name <= t.name) AS position,
       t.name    
  FROM TABLE t      
 WHERE t.name = 'Beta'

...会给关系相同的值。 IE:如果第二个位置有两个值,当第一个查询将位置 2 分配给其中一个,将 3 分配给另一个时,它们的位置都会为 2...

【讨论】:

  • @actual:没什么可说的——除了转向支持分析功能的竞争对手(PostgreSQL、Oracle、SQL Server、DB2...)之外别无选择
  • @OMGPonies 在position 后面忘了一个逗号,但它很完美。
  • 我知道这是一篇很老的帖子,但我需要一个类似的解决方案。但是,当使用内部连接、分组依据和排序依据时,“位置”字段会忽略这些,并且值都混淆了。有什么解决办法吗?
  • @Daniel 你应该问一个新问题,也许可以参考这个。
  • @actual,因为这是对单行的查询,所以这里不应该存在重大的性能问题。如果您想获得完整列表的排名,情况会有所不同,但您可以“作弊”并通过按点排序来使用隐式排名。
【解决方案4】:

如果查询很简单并且返回的结果集可能很大,那么您可以尝试将其拆分为两个查询。

第一个查询使用缩小过滤条件仅检索该行的数据,第二个查询使用COUNTWHERE 子句来计算位置。

例如你的情况

查询 1:

SELECT * FROM tbl WHERE name = 'Beta'

查询 2:

SELECT COUNT(1) FROM tbl WHERE name &gt;= 'Beta'

我们在具有 2M 记录的表中使用这种方法,这比 OMG Ponies 的方法更具可扩展性。

【讨论】:

    【解决方案5】:

    表格中一行的位置表示有多少行比目标行“更好”。

    因此,您必须计算这些行数。

    SELECT COUNT(*)+1 FROM table WHERE name

    如果出现平局,则返回最高位置。

    如果您在现有“Beta”行之后添加另一行同名“Beta”,则返回的位置仍为 2,因为它们在分类中的位置相同。

    希望这对将来会搜索类似内容的人有所帮助,因为我相信问题所有者已经解决了他的问题。

    【讨论】:

      【解决方案6】:

      我有一个非常相似的问题,这就是为什么我不会问同样的问题,但我会在这里分享我做了什么,我还必须使用 group by 和 order by AVG。 有学生,有签名和socore,我必须对他们进行排名(换句话说,我首先计算AVG,然后在DESC中排序,最后我需要添加位置(对我来说排名),所以我做了与这里的最佳答案非常相似,稍作改动以适应我的问题):

      我最后将position(对我来说排名)列放在外部 SELECT 中

      SET @rank=0;
      SELECT @rank := @rank + 1 AS ranking, t.avg, t.name
        FROM(SELECT avg(students_signatures.score) as avg, students.name as name
      FROM alumnos_materia
      JOIN (SELECT @rownum := 0) r
      left JOIN students ON students.id=students_signatures.id_student
      GROUP BY students.name order by avg DESC) t 
      

      【讨论】:

      • 这个答案比接受的答案更容易理解。 +1
      【解决方案7】:

      其他答案对我来说似乎太复杂了。

      这里有一个简单示例,假设您有一个包含列的表格:

      userid | points
      

      并且您想按点对用户 ID 进行排序并获取行位置(用户的“排名”),然后使用:

      SET @row_number = 0;
      
      SELECT 
          (@row_number:=@row_number + 1) AS num, userid, points
      FROM
          ourtable
      ORDER BY points DESC
      

      num 为您提供行位置(排名)。

      如果您有 MySQL 8.0+,那么您可能想要使用 ROW_NUMBER()

      【讨论】:

        【解决方案8】:

        我正在通过接受的答案,它似乎有点复杂,所以这里是它的简化版本。

        SELECT t,COUNT(*) AS position FROM t      
         WHERE name <= 'search string' ORDER BY name
        

        【讨论】:

          【解决方案9】:

          我有类似类型的问题,我需要表 order by votes desc 的排名(索引)。以下对我来说很好。

          Select *, ROW_NUMBER() OVER(ORDER BY votes DESC) as "rank"
          From "category_model"
          where ("model_type" = ? and "category_id" = ?)
          

          【讨论】:

            猜你喜欢
            • 2020-09-21
            • 1970-01-01
            • 2021-02-17
            • 2012-09-02
            • 2015-09-22
            • 2013-09-24
            • 2011-07-18
            • 2015-02-26
            • 1970-01-01
            相关资源
            最近更新 更多