MySQL 中,ON DUPLICATE KEY UPDATE 是一个非常实用的语法,用来实现**“存在则更新,不存在则插入”**的逻辑,尤其在批量导入或同步数据时很常用。


1. 基本语法

INSERT INTO table_name (col1, col2, ...)
VALUES (val1, val2, ...)
ON DUPLICATE KEY UPDATE col1 = new_val1, col2 = new_val2;
  • 触发条件:插入时遇到主键(PRIMARY KEY)或唯一索引(UNIQUE KEY)冲突
  • 执行逻辑
    • 没有冲突 → 正常插入
    • 有冲突 → 执行 UPDATE 中的更新语句

2. 示例

假设有一个用户表:

CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    age INT,
    UNIQUE KEY unique_name (name)
);

插入或更新

INSERT INTO users (id, name, age)
VALUES (1, 'Alice', 20)
ON DUPLICATE KEY UPDATE age = VALUES(age);
  • 如果 id=1name='Alice' 已存在 → 更新 age
  • 否则 → 插入新数据

3. 使用 VALUES() 引用插入值

UPDATE 部分,可以直接用 VALUES(col_name) 引用插入时提供的值:

ON DUPLICATE KEY UPDATE
    age = VALUES(age),
    name = VALUES(name);

MySQL 8.0.19+ 中 VALUES() 已废弃,改用 NEW.col_nameAS 语法:

INSERT INTO users (id, name, age)
VALUES (1, 'Alice', 25) AS new
ON DUPLICATE KEY UPDATE age = new.age;

4. 批量插入 + 更新

INSERT INTO users (id, name, age)
VALUES
    (1, 'Alice', 25),
    (2, 'Bob', 30),
    (3, 'Cathy', 28)
ON DUPLICATE KEY UPDATE
    age = VALUES(age);

一次插入多条记录,如果冲突则批量更新。


5. 常用技巧

自增字段计数

INSERT INTO stats (id, count)
VALUES (1, 1)
ON DUPLICATE KEY UPDATE count = count + 1;

如果存在则计数加一。


更新多个字段

ON DUPLICATE KEY UPDATE
    name = VALUES(name),
    age = VALUES(age),
    last_update = NOW();

和唯一索引配合

ON DUPLICATE KEY UPDATE 依赖主键或唯一索引冲突
例如:

CREATE UNIQUE INDEX uniq_email ON users(email);

这样用 email 冲突时也能触发更新。


6. 注意事项

  1. 必须有主键或唯一索引才能触发
  2. 可能会触发 两次写入(一次尝试插入,一次更新),所以会影响自增 ID
  3. 如果不希望影响 AUTO_INCREMENT,可考虑 INSERT ... ON DUPLICATE KEY UPDATE id=id
  4. MySQL 8.0.19+ 推荐用 AS new 代替 VALUES()