mysql - 为什么 MySQL 5.7 order by 会影响临时排名列?

标签 mysql sql-order-by mysql-variables

我需要生成一份按离职百分比排序的员工列表。我构建了以下存储过程:

SET @cnt = 0;
SET @percent = 2.0;

SELECT
    CASE
        WHEN stats.close/(stats.open+stats.close) = @percent THEN @cnt
        ELSE (@cnt := @cnt + 1) 
    END rank,
    stats.employee,
    stats.close,
    stats.open,
    (@percent := stats.close/(stats.open+stats.close)) percent
         FROM stats
              WHERE stats.date = CURDATE()
                   ORDER BY percent

返回

| Rank | Employee | Close | Open | Percent|  
|     1|    Smith|       9|     1|    0.90|  
|     2|    Jones|      75|    25|    0.75|  
|     3|      Zed|       1|     9|    0.10|  
|     3|    Adams|      10|    90|    0.10|

此查询可用于其预期目的,但在查看查询后,它似乎不应正确返回。这就是我这么认为的原因:

MySQL 在处理 ORDER BY 之前处理 SELECT。因此,我假设 MySQL 会按照它决定从数据库中出来的任何顺序分配排名,然后对结果集进行排序。我希望它看起来像这样:

| Rank | Employee | Close | Open | Percent|  
|     3|    Smith|       9|     1|    0.90|  
|     2|    Jones|      75|    25|    0.75|  
|     4|      Zed|       1|     9|    0.10|  
|     1|    Adams|      10|    90|    0.10|

为什么不是这样?

最佳答案

以任何顺序使用@variables 严格来说并不可靠,但它是模仿 MySQL 仍然缺乏的窗口函数的常见“hack”(为 v8.x 计划,即仍处于预发布阶段)。

这个“hack”依赖于 ORDER BY 与 SELECT 一起处理(不是作为 2 个不同的步骤)它们比您预期的更集成。例如

SELECT * 
FROM   (SELECT CASE 
                 WHEN stats.close / ( stats.open + stats.close ) = @percent THEN 
                 @cnt 
                 ELSE ( @cnt := @cnt + 1 ) 
               end                                                        rank, 
               stats.employee, 
               stats.close, 
               stats.open, 
               ( @percent := stats.close / ( stats.open + stats.close ) ) 
               percent 
        FROM   stats 
        CROSS JOIN (@percent := 0 x, @cnt :=0 y) vars
        WHERE  stats.date = Curdate() 
        ORDER  BY percent ASC) d 
ORDER  BY percent DESC 

内部顺序 percent ASC 将设置从最低百分比值开始的排名,然后外部顺序将最高百分比排在第一位。

真正的问题是不能保证 select 子句中从左到右(或从上到下,如上所示)的表达式顺序。所以有可能@percent 比较计算@cnt 并没有按照写的sql 所示的方式进行。实际上,它“大部分时间”都有效,但也可能无效。 (所以打开窗口函数!!)

关于mysql - 为什么 MySQL 5.7 order by 会影响临时排名列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47045759/

相关文章:

php - 尝试在php中动态创建一个纬度和经度数组

mysql - 根据条件排序 MYSQL 结果

Tsql,union 改变结果顺序,union all 不

mysql - 获取每组分组结果的前n条记录

mysql - 按分数对 mysql 中的用户进行排名

php - sql 如果之前不存在则最好插入行

mysql - Laravel:试图获得非对象的属性

php - SQL:论坛按行为排序(在 Codeigniter 中)

php - 更新表的单列,值应该从0开始,然后递增1

mysql - 是什么迫使我的系统在 "/opt/local/var/run/mysqld/mysqld.sock"中查找 MySQL