【问题标题】:With MySQL, how can I generate a column containing the record index in a table?使用 MySQL,如何在表中生成包含记录索引的列?
【发布时间】:2011-03-08 19:19:25
【问题描述】:

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

我希望能够通过一个名为 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) 

派生出来的

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

有什么想法吗?

【问题讨论】:

  • 行是文件名还是要按主键排序?
  • 在 SQL 中,行号真的不重要。你应该做的是向你的表添加一个自动递增的主键。
  • 主键不应该是行标识符,因为它们对于实际行位置不可靠。
  • 此外,由于行号是分数的函数,我认为它不是静态值,因此将其设为自动递增值(主键与否)不会给出预期结果。跨度>
  • 你可能想保存丑陋的自定义函数,见datamakessense.com/mysql-rownum-row-number-function

标签: mysql indexing


【解决方案1】:

您可能想尝试以下方法:

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)

【讨论】:

  • 您还可以通过用逗号替换JOIN 语句来初始化@curRow,如下所示:FROM league_girl l, (SELECT @curRow := 0) r
  • @Mike:确实如此。这可能也更整洁。感谢您分享此提示。
  • @smhnaji MySQL 要求每个“派生表”都有一个名称。我决定称它为“r”:) ...在这种情况下它没有什么用途,但您通常会使用它来引用派生表的属性,就好像它是一个真实的表一样。
  • 人们应该知道,这个行号是在任何排序发生之前计算出来的,所以如果订单改变了行的顺序,数字可能会变得混乱。
  • 有没有办法在ORDER BY之后计算得到这个行号?
【解决方案2】:
SELECT @i:=@i+1 AS iterator, t.*
FROM tablename t,(SELECT @i:=0) foo

【讨论】:

  • 有没有办法让迭代器列是整数而不是小数?
【解决方案3】:

我使用的模板结构如下:

  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

【讨论】:

  • 完美,魅力和模板之类的作品可以与子查询作为参数重用..
  • 如果您的基本查询使用 GROUP BY,此解决方案也适用
【解决方案4】:

你也可以使用

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

初始化计数器变量。

【讨论】:

  • @curRow 可能仍具有您上次在当前会话中运行此查询时的值。
  • 是的,但前提是您在同一个连接实例上重新查询。关闭连接后会自动释放局部变量。
  • 是的,这就是我所说的“在当前会话中”的意思。
【解决方案5】:

假设 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;

对于大量显示的结果,这会有点慢,你会想改用自加入。

【讨论】:

    【解决方案6】:

    如果您只是想在按字段分数排序后知道某个特定用户的位置,您可以简单地从表中选择字段分数高于当前用户分数的所有行。并使用返回的行号 + 1 来知道当前用户的位置。

    假设你的表是league_girl,你的主字段是id,你可以这样使用:

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

    【讨论】:

      【解决方案7】:

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

      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 服务器处理此查询或获取整个表并让应用程序/Web 服务器操作行来获得更好的结果事后。

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

      【讨论】:

        【解决方案8】:

        我知道 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));
        }
        

        【讨论】:

          猜你喜欢
          • 2016-01-26
          • 1970-01-01
          • 2020-04-14
          • 1970-01-01
          • 2020-10-12
          • 1970-01-01
          • 1970-01-01
          • 2011-01-25
          相关资源
          最近更新 更多