我试图回答另一个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 manual。 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) |
现在,我的问题是:
如何在{(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语句。
答案 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';
关于“魔术弦”的某种形式:)