使用MySQL,如何生成包含表中记录索引的列?


100

有什么办法可以从查询中获取实际的行号?

我希望能够通过一个名为score的字段来订购一个名为League_girl的表;并返回用户名和该用户名的实际行位置。

我想对用户进行排名,以便我可以告诉特定用户在哪里,即。乔在200中排名100,即

User Score Row
Joe  100    1
Bob  50     2
Bill 10     3

我在这里看到了一些解决方案,但是我已经尝试了大多数解决方案,但实际上没有一个返回行号。

我已经试过了:

SELECT position, username, score
FROM (SELECT @row := @row + 1 AS position, username, score 
       FROM league_girl GROUP BY username ORDER BY score DESC) 

作为派生

...但是它似乎没有返回行位置。

有任何想法吗?


行是文件名吗?还是要按主键排序?
Sarfraz 2010年

在SQL中,行号实际上并不重要。您应该做的是向表中添加一个自动增量主键。
simendsjo 2010年

9
主键绝不应该有行标识符,因为它们对于实际的行位​​置不可靠。
TheBounder 2010年

3
此外,由于行号是我认为不是静态值的分数的函数,因此使其成为自动递增的值(无论是否为主键)都不会得到预期的结果。
kasperjj

您可能想要保存丑陋的自定义函数,请参见datamakessense.com/mysql-rownum-row-number-function
AdrianBR 2014年

Answers:


174

您可能需要尝试以下方法:

SELECT  l.position, 
        l.username, 
        l.score,
        @curRow := @curRow + 1 AS row_number
FROM    league_girl l
JOIN    (SELECT @curRow := 0) r;

JOIN (SELECT @curRow := 0)部分允许变量初始化,而无需单独的SET命令。

测试用例:

CREATE TABLE league_girl (position int, username varchar(10), score int);
INSERT INTO league_girl VALUES (1, 'a', 10);
INSERT INTO league_girl VALUES (2, 'b', 25);
INSERT INTO league_girl VALUES (3, 'c', 75);
INSERT INTO league_girl VALUES (4, 'd', 25);
INSERT INTO league_girl VALUES (5, 'e', 55);
INSERT INTO league_girl VALUES (6, 'f', 80);
INSERT INTO league_girl VALUES (7, 'g', 15);

测试查询:

SELECT  l.position, 
        l.username, 
        l.score,
        @curRow := @curRow + 1 AS row_number
FROM    league_girl l
JOIN    (SELECT @curRow := 0) r
WHERE   l.score > 50;

结果:

+----------+----------+-------+------------+
| position | username | score | row_number |
+----------+----------+-------+------------+
|        3 | c        |    75 |          1 |
|        5 | e        |    55 |          2 |
|        6 | f        |    80 |          3 |
+----------+----------+-------+------------+
3 rows in set (0.00 sec)

19
您还可以@curRow通过用JOIN逗号替换语句来初始化,例如:FROM league_girl l, (SELECT @curRow := 0) r
Mike

2
@迈克:是的。而且这可能也更整洁。感谢您分享此提示。
丹尼尔·瓦萨洛

2
@smhnaji MySQL要求为每个“派生表”指定一个名称。我决定将其命名为“ r” :) ...在这种情况下,它没有什么用,但是您通常会使用它来引用派生表的属性,就好像它是真实表一样。
丹尼尔·瓦萨洛

20
人们应该意识到,此行号是在进行任何排序之前计算出来的,因此,如果顺序更改了行顺序,则该行号可能会变得混乱。
Grim ... 2012年

7
有没有一种方法可以获取在ORDER BY?之后计算出的行号?
Pierre de LESPINAY,2012年

38
SELECT @i:=@i+1 AS iterator, t.*
FROM tablename t,(SELECT @i:=0) foo

有没有办法做到这一点,以使迭代器列是整数而不是十进制?
kraftydevil

7

这是我使用的模板的结构:

  select
          /*this is a row number counter*/
          ( select @rownum := @rownum + 1 from ( select @rownum := 0 ) d2 ) 
          as rownumber,
          d3.*
  from 
  ( select d1.* from table_name d1 ) d3

这是我的工作代码:

select     
           ( select @rownum := @rownum + 1 from ( select @rownum := 0 ) d2 ) 
           as rownumber,
           d3.*
from
(   select     year( d1.date ), month( d1.date ), count( d1.id )
    from       maindatabase d1
    where      ( ( d1.date >= '2013-01-01' ) and ( d1.date <= '2014-12-31' ) )
    group by   YEAR( d1.date ), MONTH( d1.date ) ) d3

完美的,就像魅力和模板作品可以用重复使用子查询作为参数..
Zavael

如果您的基本查询使用GROUP BY
Dave R

4

您也可以使用

SELECT @curRow := ifnull(@curRow,0) + 1 Row, ...

初始化计数器变量。


3
@curRow可能仍具有您上次在当前会话中运行此查询以来的值。
比尔·卡温

是的,但仅当您在同一连接实例上重新查询时才如此。连接关闭后,将自动处理局部变量。
炉边2014年

是的,这就是我在“当前会话”中说的意思。
Bill Karwin 2014年

3

假设MySQL支持它,您可以使用标准的SQL子查询轻松地做到这一点:

select 
    (count(*) from league_girl l1 where l2.score > l1.score and l1.id <> l2.id) as position,
    username,
    score
from league_girl l2
order by score;

对于大量显示的结果,这会有点慢,您需要改用自连接。


3

如果您只是想按字段得分来了解一位特定用户的位置,则只需从表中选择字段得分高于当前用户得分的所有行。并使用返回的行号+ 1来知道此当前用户的位置。

假设您的表为,league_girl而主字段为id,则可以使用以下命令:

SELECT count(id) + 1 as rank from league_girl where score > <your_user_score>

0

我发现原始答案非常有用,但我也想根据要插入的行号来抓取一组特定的行。这样,我将整个原始答案包装在一个子查询中,以便可以引用要插入的行号。

SELECT * FROM 
( 
    SELECT *, @curRow := @curRow + 1 AS "row_number"
    FROM db.tableName, (SELECT @curRow := 0) r
) as temp
WHERE temp.row_number BETWEEN 1 and 10;

在子查询中有一个子查询不是很有效,因此值得测试一下,让SQL Server处理该查询,还是获取整个表并让应用程序/ Web服务器在事后处理行,以获得更好的结果。 。

就我个人而言,我的SQL Server并不太忙,因此最好让它处理嵌套的子查询。


0

我知道OP正在寻求mysql答案,但由于我发现其他答案对我不起作用,

  • 他们大多数都失败了 order by
  • 否则,它们的效率非常低下,并且对于胖表的查询非常慢

因此,为节省像我这样的其他人的时间,只需在从数据库中检索它们后对其进行索引

PHP中的示例:

$users = UserRepository::loadAllUsersAndSortByScore();

foreach($users as $index=>&$user){
    $user['rank'] = $index+1;
}

PHP中使用偏移量和分页限制的示例:

$limit = 20; //page size
$offset = 3; //page number

$users = UserRepository::loadAllUsersAndSortByScore();

foreach($users as $index=>&$user){
    $user['rank'] = $index+1+($limit*($offset-1));
}
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.