前方危险:MySQL UPDATE 语句的非标准实现

作者: 不剪发的Tony老师
毕业于北京航空航天大学,十多年数据库管理与开发经验,目前在一家全球性的金融公司从事数据库架构设计。CSDN学院签约讲师以及GitChat专栏作者。csdn上的博客收藏于以下地址:https://tonydong.blog.csdn.net


文章目录

大家好!我是只谈技术不剪发的 Tony 老师。

今天给大家介绍一下 MySQL 数据库中 UPDATE 语句和 SQL 标准(以及其他数据库)实现上的一个差异。如果我们没有注意到这个问题,很可能会导致意料之外的结果。

如果觉得文章有用,欢迎评论📝、点赞👍、推荐🎁

我们首先创建一个简单的示例表:

CREATE TABLE t1(
  id int,
  col1 int,
  col2 int
);

INSERT INTO t1 VALUES (1, 1, 1);

SELECT * FROM t1;
id|col1|col2|
--|----|----|
 1|   1|   1|



然后,我们对表 t1 中的数据进行更新:

UPDATE t1
SET col1 = col1 + 1,
    col2 = col1
WHERE id = 1;

SELECT col1, col2
FROM t1;



请问查询语句返回的 col1 和 col2 字段的结果分别是什么?

    对于 SQL 标准以及其他数据库的实现,结果分别为 2 和 1。
    但是对于 MySQL,结果分别为 2 和 2!

对于 MySQL 而言,如果 UPDATE 语句在表达式中(col2 = col1)使用了前面被更新的字段(col1),将会使用该字段被更新后的值(2)而不是原来的值(1)。

注意,MySQL 这种实现方式和 SQL 标准不同。另外我们还测试了其他数据库,包括 Oracle、Microsoft SQL Server、PostgreSQL 以及 SQLite,它们的实现都遵循了 SQL 标准。

如果我们想要在 MySQL 中实现和标准 SQL 相同的效果,可以在 UPDATE 语句中调整一下被更新字段的顺序。例如:

UPDATE t1
SET col2 = col1,
    col1 = col1 + 1
WHERE id = 1;


这样一来,字段 col2 在 col1 之前更新,使用的是 col1 旧值(1),得到的结果和 SQL 标准一致。

结束语:一般在编写 UPDATE 语句时,我们不需要关心多个字段的更新顺序。但是由于 MySQL 实现的问题,我们需要注意它们的语法顺序。