使用 JOIN / 多表 UPDATE 访问同一查询中先前更新的列的行为不同
Posted
技术标签:
【中文标题】使用 JOIN / 多表 UPDATE 访问同一查询中先前更新的列的行为不同【英文标题】:Accessing a previously updated column in the same query behaves differently with JOINs / multi-table UPDATEs 【发布时间】:2017-08-02 02:08:39 【问题描述】:假设我有两个表players
和stats
,内容如下:
mysql> select * from players;
+----+-------+
| id | alive |
+----+-------+
| 1 | 0 |
| 2 | 1 |
+----+-------+
mysql> select * from stats;
+--------+------+------+-------+
| player | win | lose | ratio |
+--------+------+------+-------+
| 1 | 12 | 20 | 0.6 |
| 2 | 8 | 1 | 8 |
+--------+------+------+-------+
我想增加每个玩家的win
-计数器,同时更新他们的赢/输比率。这看起来像这样:
update `stats` set `win` = `win` + 1, `ratio` = `win` / `lose`;
注意win
的增量值是用来计算ratio
的(正如这里的mysql手册所说:1.8.2.2 UPDATE Differences)。
现在,当将 JOIN 添加到 UPDATE 查询以限制它仅更新 alive = 1
的玩家时,此行为会发生变化:
update `stats` st
inner join `players` pl
on ( pl.`id` = st.`player` )
set `win` = `win` + 1, `ratio` = `win` / `lose`
where pl.`alive` = 1;
mysql> select * from stats;
+--------+------+------+-------+
| player | win | lose | ratio |
+--------+------+------+-------+
| 1 | 12 | 20 | 0.6 |
| 2 | 9 | 1 | 8 |
+--------+------+------+-------+
我找到的唯一解决方案是将 win
的新值分配给一个临时变量,并在计算 ratio
时使用该临时变量:
update `stats` st
inner join `players` pl
on ( pl.`id` = st.`player` )
set
`win` = @tmpWin := ( `win` + 1 ),
`ratio` = @tmpWin / `lose`
where pl.`alive` = 1;
为什么 MySQL 会出现这样的行为,对于此类问题是否有更优雅的解决方案(除了创建一个动态计算比率的视图)?
表的创建如下:
create table `players` (
`id` INT,
`alive` TINYINT,
primary key (`id`)
);
create table `stats` (
`player` INT,
`win` INT,
`lose` INT,
`ratio` FLOAT,
primary key (`player`)
);
我正在使用 MySQL v5.7.17
【问题讨论】:
在 5.7.17 中,您可以使用 generated columns。 【参考方案1】:我无法解释确实看起来很奇怪的连接案例的行为,但以下内容按预期工作:
UPDATE `stats`
SET `win` = `win` + 1, `ratio` = `win` / `lose`
WHERE player IN (SELECT id FROM players WHERE alive=1);
【讨论】:
以上是关于使用 JOIN / 多表 UPDATE 访问同一查询中先前更新的列的行为不同的主要内容,如果未能解决你的问题,请参考以下文章