MySQL在ORDER BY中获取行位置

时间:2010-09-01 02:33:54

标签: sql mysql analytic-functions

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

9 个答案:

答案 0 :(得分:108)

使用此:

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到1时,它们的位置都为2,而另一个的位置为3 ......

答案 1 :(得分:18)

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

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

答案 2 :(得分:8)

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

第一个带有缩小过滤条件的查询只是为了检索该行的数据,第二个查询使用带有COUNT子句的WHERE来计算位置。

例如在您的情况下

查询1:

SELECT * FROM tbl WHERE name = 'Beta'

查询2:

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

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

答案 3 :(得分:2)

我有一个非常相似的问题,这就是为什么我不会问同样的问题,但我会在这里分享我做了什么,我还必须使用一个小组,并由AVG订购。  有学生,有签名和社交,我不得不对它们进行排名(换句话说,我首先计算AVG,然后在DESC中对它们进行排序,然后最后我需要添加位置(排名为我),所以我做了这里非常相似 最佳答案

我最后在外部SELECT

中放了position(我的排名)列
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 

答案 4 :(得分:1)

表中行的位置表示比目标行“更好”的行数。

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

SELECT COUNT(*)+ 1 FROM table WHERE name&lt;'Beta'

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

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

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

答案 5 :(得分:1)

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

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

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

答案 6 :(得分:1)

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

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

答案 7 :(得分:0)

我遇到了类似的问题,需要表格order by votes desc的等级(索引)。以下对我来说很好用。

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

答案 8 :(得分:-7)

可能是您需要的添加语法

  

LIMIT

所以使用

SELECT * FROM tbl ORDER BY name ASC LIMIT 1

如果你只需要一行..