2

我需要根据该 part_id 的 build_steps 的 MAX 值创建一个排名列,其中每个不同的 part_id 的排名都与 order_id 相关联。每当迭代新的 order_id 时,都应该重新启动排名。

我有以下小提琴,但它没有正确创建排名。

http://sqlfiddle.com/#!9/63d47/29

以下是我的查询

SET @current_rank = 0;
SET @prevOrder = null;
SELECT part_id, MAX(build_steps) AS max_build_steps, 
   @current_rank:= CASE WHEN @prevOrder = order_id 
             THEN  @current_rank:=@current_rank +1 
             ELSE @current_rank:=1 END  rank,
              @prevOrder:= order_id as 'order_id'
FROM orders,
(SELECT @current_rank:=0) r   
GROUP BY order_id, part_id
ORDER BY order_id desc, max_build_steps desc;

桌子:

CREATE TABLE orders
    (`part_id` int, `build_steps` int, `order_id` int)
;

INSERT INTO orders
    (`part_id`, `build_steps`, `order_id`)
VALUES
    (234554, 1, 1234),
    (234554, 2, 1234),
    (234554, 3, 1234),
    (234554, 4, 1234),
    (234554, 5, 1234),
    (234554, 6, 1234),
    (234554, 7, 1234),
    (234554, 8, 1234),
    (234555, 1, 1234),
    (234555, 2, 1234),
    (234556, 1, 1234),
    (234556, 2, 1234),
    (234556, 3, 1234),
    (234557, 1, 1234),
    (234566, 1, 5678),
    (234566, 2, 5678),
    (234566, 3, 5678),
    (234566, 4, 5678),
    (234566, 5, 5678),
    (234567, 1, 5678),
    (234567, 2, 5678),
    (234568, 1, 5678),
    (234569, 1, 5678)
;

预期结果:

part_id, max_build_steps, rank, order_id

234566  5   1   5678

234567  2   2   5678

234568  1   3   5678

234569  1   4   5678

234554  8   1   1234

234556  3   2   1234

234555  2   3   1234

234557  1   4   1234

当前查询结果:

part_id max_build_steps rank    order_id

234566  5   1   5678

234567  2   2   5678

234568  1   3   5678

234569  1   4   5678

234554  8   1   1234

234556  3   3   1234

234555  2   2   1234

234557  1   4   1234
4

1 回答 1

1

您的问题很好地证明了对依赖于引擎执行顺序的此类任务使用会话变量是可用的。在您的情况下,MySQL 似乎在对结果集进行排序之前在 SELECT 部分执行您的操作。一种解决方法是使用有序子查询:

select part_id,
  max_build_steps,
  case when order_id = @order_id 
    then @rank := @rank + 1
    else @rank := 1
  end as rank,
  @order_id := order_id as order_id
from (
  select o.part_id, o.order_id, max(build_steps) as max_build_steps
  from orders o
  group by o.part_id, o.order_id
  order by o.order_id, max_build_steps desc
  limit 1000000000
) sub 
cross join (select @order_id := null, @rank := 0) init_session_vars

这至少适用于 MySQL 5.6的sqlfiddle 。然而,人们已经报告了一些问题,即较新的 MySQL 版本不会对子查询结果进行排序。这就是为什么我添加了一个巨大的限制,这是 MariaDB 的一种解决方法(不能说它是否适用于 MySQL 5.7)。

但是 - 您最好获取有序结果并以保证执行顺序的程序语言计算排名。

更新

这是使用临时表和 AUTO_INCREMENT 列的不同方法:

create temporary table tmp1 (
  ai int auto_increment primary key,
  part_id int, 
  order_id int,
  max_build_steps int
) select o.part_id, o.order_id, max(build_steps) as max_build_steps
  from orders o
  group by o.part_id, o.order_id
  order by o.order_id, max_build_steps desc
;

create temporary table tmp2 (order_id int, min_ai int)
  select order_id, min(ai) as min_ai
  from tmp1
  group by order_id
;

select t1.part_id,
  t1.order_id,
  t1.max_build_steps,
  t1.ai - t2.min_ai + 1 as rank
from tmp1 t1
join tmp2 t2 using(order_id);

sqlfiddle

于 2016-08-21T18:20:54.717 回答