根据属于组集的不同列的最大值创建排名列
Create a Rank Column based on the max values of a distinct column that belongs to a group set
我需要创建一个排名列,其中每个不同的 part_id 与 order_id 相关联,基于 build_steps 的最大值 [=29] =].每当迭代新的 order_id 时,排名应该重新开始。
我有以下 fiddle 但它没有正确创建排名。
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;
Table:
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
你的问题很好地证明了使用会话变量来完成依赖于引擎执行顺序的任务是可行的。在您的情况下, 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
这至少适用于 sqlfiddle 和 MySQL 5.6。然而,人们已经报告了问题,较新的 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);
我需要创建一个排名列,其中每个不同的 part_id 与 order_id 相关联,基于 build_steps 的最大值 [=29] =].每当迭代新的 order_id 时,排名应该重新开始。
我有以下 fiddle 但它没有正确创建排名。
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;
Table:
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
你的问题很好地证明了使用会话变量来完成依赖于引擎执行顺序的任务是可行的。在您的情况下, 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
这至少适用于 sqlfiddle 和 MySQL 5.6。然而,人们已经报告了问题,较新的 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);