3

我试图回答另一个SO 问题,但突然面临以下问题。应将分数分配给每个班级 ( ) 中得分最高的 3 个 ( mrk) 组 ( )。得分最高的组得5分,排名第二的得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) 或1(true),但它肯定不等于函数5的另一个参数NULLIF,因此最后只返回第一个参数 ( 5)。我选择了构造来使两个变量赋值发生而不返回任何内容。

好的,也许不是最直接的解决方案;-),但我确实注意为正在处理的每条记录定义每个变量一次,因为“涉及用户变量的表达式的评估顺序未定义” mysql手册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 |

为什么更新语句只为 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

我的意图是在表达式评估之前和之后记录变量的值。

这很奇怪 - 我不知道为什么,但似乎当您在执行更新之前为所有变量赋值时,更新会按预期工作。
比较这两个演示:

1 - 错误:http
://sqlfiddle.com/#!2/2db3e4/1 2 - 很好:http ://sqlfiddle.com/#!2/37ff5/1

唯一的区别是更新前的这段代码:

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

某种“魔术字符串”:)

于 2013-08-25T20:42:39.360 回答