93

使用以下 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 中的行,但是只为一行加载一个可能很大的结果集似乎很浪费。

4

9 回答 9

130

用这个:

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...

于 2010-09-01T02:57:52.103 回答
20

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

SELECT `id`,
       (SELECT COUNT(*) FROM `table` WHERE `name` <= 'Beta') AS `position`,
       `name`
FROM `table`
WHERE `name` = 'Beta'
于 2010-09-01T02:37:14.953 回答
8

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

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

例如在你的情况下

查询一:

SELECT * FROM tbl WHERE name = 'Beta'

查询 2:

SELECT COUNT(1) FROM tbl WHERE name >= 'Beta'

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

于 2012-03-12T07:34:50.657 回答
6

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

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

userid | points

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

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()

于 2018-11-14T10:47:49.243 回答
3

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

所以,你必须计算那些行。

table从WHERE name<'Beta' 中选择 COUNT(*)+1

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

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

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

于 2014-05-23T16:53:13.253 回答
3

我有一个非常相似的问题,这就是为什么我不会问同样的问题,但我会在这里分享我做了什么,我还必须使用 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 
于 2017-05-04T17:42:48.870 回答
1

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

SELECT t,COUNT(*) AS position FROM t      
 WHERE name <= 'search string' ORDER BY name
于 2019-08-08T13:56:22.027 回答
1

我有类似类型的问题,我需要table 的rank( Indexorder by votes desc ) 。以下对我来说很好。

Select *, ROW_NUMBER() OVER(ORDER BY votes DESC) as "rank"
From "category_model"
where ("model_type" = ? and "category_id" = ?)
于 2020-03-26T07:18:19.950 回答
-13

可能是你需要的是添加语法

LIMIT

所以用

SELECT * FROM tbl ORDER BY name ASC LIMIT 1

如果你只需要一排..

于 2010-09-01T02:41:45.897 回答