0

我正在寻找一个汇总每个用户的前 n 个值的查询。幸运的是,我在这篇文章中找到了解决方案Sum top 5 values in MySQL 但是,我很难理解给定的解决方案,即:

SELECT driver, SUM(`position`)
FROM (SELECT driver, race, season, `position`, 
         IF(@lastDriver=(@lastDriver:=driver), @auto:=@auto+1, @auto:=1) indx 
  FROM results, (SELECT @lastDriver:=0, @auto:=1) A 
  ORDER BY driver, `position`) AS A  
WHERE indx <= 5 
GROUP BY driver ;

有人可以解释它是如何工作的,尤其是 FROM 子句之后的子查询吗?先感谢您。

4

1 回答 1

0

MySQL @variables 就像做一个设置变量的内联程序,比较然后使用结果作为下一行比较的基础......让我重新格式化您的查询以获得更好的跟踪/可读性。

SELECT 
      driver, 
      SUM(`position`)
   FROM 
      ( SELECT 
              driver, 
              race, 
              season, 
              `position`, 
              IF( @lastDriver = ( @lastDriver := driver), 
                  @auto := @auto + 1, 
                  @auto := 1) indx 
        FROM 
           results, 
           (SELECT @lastDriver := 0, 
                   @auto := 1) A 
        ORDER BY 
           driver, 
           `position`) AS A  
   WHERE 
      indx <= 5 
   GROUP BY 
      driver ;

内部“From”子句启动查询。Select @ 就像你有一个程序一样..

set @auto = 1
set @lastDriver = 0

准备变量。

因为您有一个 order by 子句,所以查询将从“结果”表中获取记录并将它们按顺序排列。这就像一个待处理的记录队列。现在,考虑通过 do/while 循环运行所有记录的查询。请记住,您的 @auto = 1 和 @lastDriver = 0 开始。

现在,查询将按顺序处理记录,并且一次一个字段就像查询说...

Add the driver to the result
add the race to the result
add the season to the result
add the `position` to the result

现在,您可能正在等待什么...... IF() 和 @ 变量发生了什么。IF() 如下所示

IF( some condition )
   add this value to the result
else
   add this value to the result

在这种情况下,@lastDriver = (@lastDriver := driver) 是伪的,例如..

set HoldLastDriver = @lastDriver
set @lastDriver = the driver of the current record being processed
if( HoldLastDriver = new value of @lastDriver -- current record driver )
   set the auto value = auto value +1
else
   set the auto value back to 1 because the driver just changed  

其结果被放入“indx”列。

所以,现在,当它到达下一行时,@lastDriver 和 @auto 已经更新并从那里继续......所以,如果你有以下数据,列表将显示值可能只是显示driver 和 auto 列,因为这是查询的关键元素。

                        BEFORE ROW PROCESSED  AFTER ROW PROCESSED
driver pos/race/season  @lastDriver @auto     @lastDriver @auto
  1     3 / A / A           0        1           1        1
  1     3 / B / A           1        1           1        2
  1     4 / D / B           1        2           1        3
  1     5 / E / D           1        3           1        4
  1     7 / F / D           1        4           1        5
  1     7 / G / D           1        5           1        6
  2     2 / A / A           1        6           2        1
  2     2 / B / A           2        1           2        2
  3     1 / A / A           2        2           3        1
  3     2 / B / A           3        1           3        2
  3     2 / D / B           3        2           3        3
  3     2 / E / D           3        3           3        4
  3     3 / F / D           3        4           3        5
  3     3 / G / D           3        5           3        6

要结束查询,现在所有这些记录都已处理,您的外部查询将处理驱动程序和 sum(),但仅适用于“indx”(@auto 的 AFTER 版本)小于或等于 5 的记录...因此,@auto 为 6 的两条记录(驱动程序 1 和 3)不会在结果总和中考虑。

于 2013-07-27T20:04:15.253 回答