2

その part_id の build_steps の MAX 値に基づいて、order_id に関連付けられている各 part_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 に答える