mysql插入冲突转更新ON DUPLICATE KEY UPDATE

本文详细介绍了MySQL中的INSERT ... ON DUPLICATE KEY UPDATE语法,用于在插入数据时处理主键或唯一键冲突。通过示例展示了单条记录和多条记录的插入操作,并解释了在冲突发生时如何执行更新。此外,还讨论了受影响行数的值在不同情况下的变化,以及此功能在数据同步和订单状态更新等场景中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

背景:

语法:

单条记录插入:

多条记录插入:

细节:

使用场景:


背景:

mysql利用insert插入数据时,可能发生主键/唯一键冲突,若想在冲突时变更为update语句,可以借助于mysql的INSERT ... ON DUPLICATE KEY UPDATE语句

语法:

insert into table (key...) values(val...) on duplicate key update key1=val1,key2=val2
  • 创建表user,下面的例子都以该表为主
CREATE TABLE `user` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `user_id` INT NULL,
  `user_name` VARCHAR(45) NULL,
  `score` INT NULL,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `user_id_UNIQUE` (`user_id` ASC));
INSERT INTO user (id, user_id, user_name, score) VALUES (66, 1, 'tom', 97);
INSERT INTO user (id, user_id, user_name, score) VALUES (67, 2, 'marry', 95);
id【自增主键】user_id【唯一键】user_namescore
661tom        97
672marry95

单条记录插入:

        user_id为唯一键

insert into user (user_id,user_name,score) values(1,'tom',100) on duplicate key update score = 100
  • 前半段sql是正常的insert语句
  • 后半段sql从on duplicate key开始,update将会在主键/唯一键冲突时执行。
  • 即若数据库中已经存在user_id=1的数据,将会执行update操作,将user_id=1数据中的score改为100

多条记录插入:

        user_id为唯一键

insert into user (user_id,user_name,score) values(1,'tom',100),(2,'marry',99) 
on duplicate key update score = values(score)

insert into user (user_id,user_name,score) values(1,'tom',100),(2,'marry',99) 
on duplicate key update score = values(user_id)

insert into user (user_id,user_name,score) values(1,'tom',100),(2,'marry',99) 
on duplicate key update score = values(user_id) + values(score)

insert into user (user_id,user_name,score) values(1,'tom',100),(2,'marry',99) 
on duplicate key update score = values(66)
  • 多条记录插入时,需要利用values函数处理赋值
    • values内可以直接使用字段名,可以是当前被赋值的字段(正常情况),也可以是其他字段
    • values内还可以是具体的常量值
    • 可以使用多个数字类型的字段经过values处理后再进行运算

细节:

  • 在使用insert into ... on duplicate key update插入/更新数据时,affected-rows在不同情况下的值不同,下面以插入单条记录为例
    • 当数据成功插入时(没有冲突),affected-rows=1(仅有insert一个操作,插入n条记录就是n)
    • 当数据发生冲突并更新成功时,affected-rows=2(包含delete和update操作,插入n条记录就是2*n)
    • 当数据发生冲突,更新内容与原数据一致时,affected-rows=0。若开启了CLIENT_FOUND_ROWS,affected-rows=1(冲突记录数量,n条记录冲突就是n)
  • 在冲突update时,若表中存在自增字段,自增字段也会+1(不管affects-rows是否>0)
    • 若id为自增,当前id为67,先执行一条有冲突的语句,此时自增id已经到68(原数据的id不会自增,只是自增id的计数器会+1)
    • 再插入一条新的记录,此时新纪录的id为69
# 插入冲突数据,执行update,当前最新id自增
insert into user (user_id,user_name,score) values(2,'marry',87) on duplicate key update score = 87

# 插入一条新数据
insert into user (user_id,user_name,score) values(3,'kiti',99) 
id【自增主键】user_id【唯一键】user_namescore
661tom        97
672marry95
693kiti        99


使用场景:

  • 数据时常变更,需要定时同步到mysql中,主键/唯一键一般不会修改或较少修改时,该方法可以代替delete + insert。
    • 比如学生最新成绩表,需要同步最新一次考试的分数,学生id主键一般不会变更频繁,利用on duplicate key刷新学生分数
  • 表中某些字段需要插入以及阶段性变更时,可以利用insert into ... on duplicate key 代替insert和update两种操作
    • 如订单记录表,生成订单需要插入表,同时需要阶段性的修改订单状态(下单、付款、完成等等),订单记录id又是唯一键,此时可以利用该方法实现两种业务操作
  • 待补充......

参考mysql5.7官方文档:MySQL :: MySQL 5.7 Reference Manual :: 13.2.5.2 INSERT ... ON DUPLICATE KEY UPDATE Statement

### 解决方案 在 MySQL 中,`ON DUPLICATE KEY UPDATE` 是一种用于处理重复键冲突的机制。当插入数据时遇到唯一索引或主键冲突时,MySQL 会执行指定的更新操作。然而,默认情况下,如果字段被设置为 `NULL` 或者未显式定义更新逻辑,则该字段可能不会按照预期行为更新。 为了确保字段不因 `NULL` 值而跳过更新,可以采用以下方法: #### 方法一:使用条件表达式 通过在 `ON DUPLICATE KEY UPDATE` 子句中引入条件判断来避免 `NULL` 被写入数据库。例如,可以通过 `IF()` 函数实现[^1]: ```sql INSERT INTO tbl_example (id, value) VALUES (1, NULL) ON DUPLICATE KEY UPDATE value = IF(VALUES(value) IS NOT NULL, VALUES(value), value); ``` 在此示例中,只有当新值 (`VALUES(value)`) 不为 `NULL` 时才会更新目标列;否则保留原值。 #### 方法二:利用 COALESCE() 函数替代 IF() 另一种更简洁的方式是应用 SQL 的内置函数 `COALESCE()` 来完成相同功能: ```sql INSERT INTO tbl_example (id, value) VALUES (1, NULL) ON DUPLICATE KEY UPDATE value = COALESCE(VALUES(value), value); ``` 这里 `COALESCE()` 返回第一个非空参数作为最终结果[^2]。 #### 方法三:预设默认值于应用程序层面上 考虑到某些场景下无法直接修改SQL语句本身,在这种情形之下可以在程序端预先设定好合理的缺省数值再提交给数据库服务器进行存储操作前的数据准备阶段就做好相应的处理工作从而规避掉因为传入null而导致的问题发生几率大大降低同时也能提高整体系统的健壮性可维护程度. --- ### 注意事项 - 如果表结构允许某列为 `NULL` 并且业务逻辑确实需要支持这种情况下的覆盖更新,请务必确认所使用的解决方案能够满足具体需求。 - 对性能敏感的应用应测试不同实现方式的影响以便选取最优策略[^3]. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-王尚可-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值