我需要根据该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
答案 0 :(得分: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);