开心一刻

  今天,她给我打来电话

  她:你明天陪我去趟医院吧

  我:怎么了

  她:我怀孕了,陪我去打胎

  我:他的吗

  她:嗯

  我心一沉,犹豫了片刻:生下来吧,我养!

  她:他的孩子,你不配养!

  我:我随孩子姓

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_SQL

需求背景

  最近接到一个数据迁移的需求,旧系统的数据迁移到新系统;旧系统不会再新增业务数据,业务操作都在新系统上进行

  为了降低迁移的影响,数据进行分批迁移,也就是说新旧系统会并行一段时间

  数据分批不是根据 id 范围来分的,也就说每批数据的 id 都是无规律的

  另外,为了保证新旧系统数据的对应,新系统的 id 尽可能的沿用旧系统的 id

  因为表 id 在新旧系统都是自增的,所以迁移的时候,旧系统的 id 可能在新系统已经被占用了,类似如下

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_UPDATE_02

  需求描述

  数据迁移的时候,尽可能沿用旧系统的 id,而冲突的 id 需要进行批量调整

如何调整这批冲突的 id,正是我当下要实现的需求

  我的实现是根据业务数据的增长情况,结合目前新系统的最大 id 来预设一个起始的 id

  

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_sql_03

SQL

  需求实现

  有小伙伴可能觉得,这还不简单?

  不就 5 条数据嘛,这么写不就搞定了

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_SQL_04

  多简单的事,还铺垫那么多,楼主你到底会不会?

  楼主此刻幡然醒悟:小伙伴,你好厉害哇哦

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_SQL_05

  但是如果冲突的数据很多了(几百上千),你也这样一条一条改?

  如果你真这样做,我是真心佩服你

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_SQL_06

  很显然,理智的小伙伴更多

  那该如何实现了?

UPDATE 来实现,直接上 SQL

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_字段_07

  我们来看实际案例

tbl_batch_update

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_sql_08

  数据如下

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_字段_09

  执行效果如下

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_SQL_10

  更新之后

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_字段_11

  更严谨点

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_字段_12

 

UPDATE 是不是也支持 ORDER BY

  还真支持,如下所示

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_UPDATE_13

UPDATE 的时候,基本没结合 ORDER BY ,也没尝试过结合 LIMIT

UPDATE

UPDATE

MySQL 8.0 的官方文档 ​​UPDATE Statement​​ 整理而来,推荐大家直接去看官方文档

  单表语法

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_数据_14

 

   是不是有很多疑问:

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_字段_15

  多表语法

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_SQL_16

ORDER BY 和  LIMIT

  LOW_PRIORITY

UPDATE 的修饰符之一,用来降低 SQL

LOW_PRIORITY 之后, UPDATE

LOW_PRIORITY ,表级锁的存储引擎包括: MyISAM 、 MEMORY 和 MERGE ,所以最常用的 InnoDB

  使用场景很少,混个眼熟就好

  IGNORE

UPDATE 的修饰符之一,用来声明 SQL

IGNORE , UPDATE

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_SQL_17

9002 更新成 9003 的时候,主键冲突,整个 UPDATE 中止, 9000 更新成的 9001 会回滚, 9003 ~ 9005

IGNORE

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_字段_18

UPDATE

2

IGNORE 的信息,请查看:​​The Effect of IGNORE on Statement Execution​

  关于使用场景,在新旧系统并行,做数据迁移的时候可能会用到,主键或者唯一键冲突的时候直接忽略

  ORDER BY

UDPATE

UPDATE 其实有两个阶段: 查阶段 、 更新阶段

WHERE

ORDER BY 就和 SELECT 中的 ORDER BY

  关于使用场景,大家可以回过头去看看前面讲到的的需求背景,

IGNORE 的案例 1 中的报错,其实也可以用 ORDER BY

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_UPDATE_19

  LIMIT

LIMIT row_count 子句是行匹配限制。一旦找到满足 WHERE 子句的 row_count

LIMIT 限制的是 查阶段 ,与 更新阶段

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_SQL_20

注意:与 SELECT 语法中的 LIMIT

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_SQL_21

  还是有区别的

  value DEFAULT

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_SQL_22

UPDATE 中 SET 子句的 value 是表达式,我们可以理解,这个 DEFAULT

NOT NULL ,然而我们更新这列成 NULL

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_sql_23

  会发生什么

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_字段_24

 

 

SQL_MODE ,执行 SELECT @@sql_mode;

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_sql_25

STRICT_TRANS_TABLES 表明启动了严格模式,对 INSERT 和 UPDATE 语句的 value

  如果我们关闭严格模式,再看看执行结果

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_UPDATE_26

name 字段声明成了 NOT NULL ,非严格 SQL 模式下,将 name 设置成 NULL 是成功的,但更改的值并非 NULL ,而是 VARCHAR 类型的默认值: 空字符串('')

  小结下

NOT NULL 的字段设置 NULL

NOT NULL 的字段设置 NULL

  关于字段类型的默认值,可查看:​​Data Type Default Values​

sql_mode ,可查看:​​Server SQL Modes​

MySQL 一般都是严格模式,所以大家知道有 value DEFAULT

  SET 字段顺序

SQL

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_字段_27

  想必大家都很清楚

SQL 中的 name

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_字段_28

  我们来看下结果

记一次批量更新整型类型的列值 → 探究 UPDATE 的使用细节_UPDATE_29

name

UPDATE 的 SET 是从左往右进行的,然而多表 UPDATE 却不是,多表 UPDATE

总结

UPDATE ,还是 DELETE

UPDATE 语法中的 LOW_PRIORITY 很少用, IGNORE 偶尔用, ORDER BY 和 LIMIT

sql_mode

参考

  ​​UPDATE Statement​