如何在UPDATE语句中使用用户定义的变量?

时间:2013-08-25 14:09:56

标签: mysql

我试图回答另一个SO question并突然面临以下问题。应将点数分配给每个班级(mrk)的3个最高得分(grp)组(sec)。得分最高的得分为5分,第二得分为3分,第三等级的得分为1分。对于所有其他人pts应设置为null

| 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 manualselect确实给了我想要的

结果:

| 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) |

现在,我的问题是:

如何在{(1}}列中存储上述计算结果的相同行中撰写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

为什么update语句只为pts获得单个值(5)?!?

您可以在我的SQLfiddle中找到所有数据和SQL语句。

1 个答案:

答案 0 :(得分:1)

我试图调试这个案例 我在tbl表中添加了6个新列: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';

关于“魔术弦”的某种形式:)