3

別のSOの質問に答えようとしていたところ、突然次の問題に直面しました。ポイントは、各クラス ( ) の最高得点 ( mrk) の 3 つのグループ ( ) に割り当てる必要があります。最高得点のグループは 5 ポイント、2 位のグループは 3 ポイント、3 位のグループは 1 ポイントを獲得します。その他はすべてに設定する必要があります。grpsecptsnull

| ID | SEC | GRP | MRK |    PTS |
|----|-----|-----|-----|--------|
|  1 | cl2 |  ge |  32 | (null) |
|  2 | cl1 |  gb |  22 | (null) |
|  3 | cl1 |  gd |  22 | (null) |
|  4 | cl1 |  ge |  18 | (null) |
|  5 | cl2 |  ga |  26 | (null) |
|  6 | cl1 |  ga |  55 | (null) |
|  7 | cl2 |  gb |  66 | (null) |
|  8 | cl2 |  gc |  15 | (null) |
|  9 | cl1 |  gc |  12 | (null) |
| 10 | cl2 |  gf |   5 | (null) |
| 11 | cl2 |  ge |  66 | (null) |

割り当てスキームに関して最大​​限の柔軟性を提供するユーザー定義変数を使用することを選択し、すぐに次の解決策を思いつきました。

SELECT id,sec,grp,mrk,
CASE WHEN @s=sec THEN          -- whenever there is a new class ...
 CASE WHEN @m=mrk THEN @i ELSE -- issue the same points for 
                               -- identical scorers, otherwise ...
  CASE WHEN IF(@m:=mrk,@i,@i)>2 THEN @i:=@i-2  -- store mrk in @mrk and 
                               -- while @i>2 return points: 3 or 1 ...
                                ELSE @i:=null  -- no points for the rest
  END
 END
 ELSE NULLIF(@i:=5,(@s:=sec)=(@m:=mrk)) -- store sec in @s and mrk in @m
                                        -- and return points: 5
END pts
FROM tbl ORDER BY sec,mrk desc

の説明NULLIF(@i:=5,(@s:=sec)=(@m:=mrk)):

@s:=sec@m:=mrkの両方が評価され、それらの値が によって比較され=ます。結果は0(false) または(true) のいずれかになりますが、関数のもう 1 つの引数である とは1明らかに等しくないため、最終的には最初の引数 ( ) のみが返されます。何も返さずに 2 つの変数の割り当てが行われるように構成を選択しました。5NULLIF5

OK、おそらく最も簡単な解決策ではないかもしれません;-)、しかし、「ユーザー変数を含む式の評価の順序は定義されていない」ため、処理中のレコードごとに各変数を1回だけ定義するように注意を払いました. 確かに私に希望を与えますselect

結果:

| ID | SEC | GRP | MRK |    PTS |
|----|-----|-----|-----|--------|
|  6 | cl1 |  ga |  55 |      5 |
|  2 | cl1 |  gb |  22 |      3 |
|  3 | cl1 |  gd |  22 |      3 |
|  4 | cl1 |  ge |  18 |      1 |
|  9 | cl1 |  gc |  12 | (null) |
|  7 | cl2 |  gb |  66 |      5 |
| 11 | cl2 |  ge |  66 |      5 |
|  1 | cl2 |  ge |  32 |      3 |
|  5 | cl2 |  ga |  26 |      1 |
|  8 | cl2 |  gc |  15 | (null) |
| 10 | cl2 |  gf |   5 | (null) |

さて、私の質問は次のとおりです。

UPDATE上記の計算結果を列に格納する同じ行に沿ってステートメントを作成するにはどうすればよいptsですか?

これまでの私の試みはすべて失敗しました:

UPDATE tbl SET pts=
CASE WHEN @s=sec THEN
 CASE WHEN @m=mrk THEN @i ELSE
  CASE WHEN IF(@m:=mrk,@i,@i)>2 THEN @i:=@i-2 
                                ELSE @i:=null 
  END
 END
 ELSE NULLIF(@i:=5,(@s:=sec)=(@m:=mrk)) 
END
ORDER BY sec,mrk desc

結果:

| ID | SEC | GRP | MRK | PTS |
|----|-----|-----|-----|-----|
|  6 | cl1 |  ga |  55 |   5 |
|  2 | cl1 |  gb |  22 |   5 |
|  3 | cl1 |  gd |  22 |   5 |
|  4 | cl1 |  ge |  18 |   5 |
|  9 | cl1 |  gc |  12 |   5 |
|  7 | cl2 |  gb |  66 |   5 |
| 11 | cl2 |  ge |  66 |   5 |
|  1 | cl2 |  ge |  32 |   5 |
|  5 | cl2 |  ga |  26 |   5 |
|  8 | cl2 |  gc |  15 |   5 |
| 10 | cl2 |  gf |   5 |   5 |

update ステートメントが pts に対して単一の値 (5) しか取得しないのはなぜですか?!?

私のSQLfiddleですべてのデータと SQL ステートメントを見つけることができます。

4

1 に答える 1

1

このケースをデバッグしようとしました。
テーブルに 6 つの新しい列を追加しましたtbl: b_s、b_m、b_i および a_s、a_m、a_i
b_* - 「前」を意味し、a_* - 「後」を意味
し、クエリを次のように変更しました。

UPDATE tbl SET 
   b_s = @s,
   b_m = @m,
   b_i = @i, 
pts=
CASE WHEN @s=sec THEN
 CASE WHEN @m=mrk THEN @i ELSE
  CASE WHEN IF(@m:=mrk,@i,@i)>2 THEN @i:=@i-2 
                                ELSE @i:=null 
  END
 END
 ELSE NULLIF(@i:=5,(@s:=sec)=(@m:=mrk)) 
END,
a_s = @s,
a_m = @m,
a_i = @i 
ORDER BY sec,mrk desc

私の意図は、式の評価の前後に変数の値を記録することでした。

奇妙です-理由はわかりませんが、更新の実行前にすべての変数に値を割り当てると、更新が期待どおりに機能するようです。 これらの2
つのデモを比較し

ください


唯一の違いは、更新前の次のコード フラグメントです。

set @i='alamakota';
set @m='alamakota';
set @s='alamakota';

「魔法のひも」に関するある種の:)

于 2013-08-25T20:42:39.360 に答える