MERGE INTO开发教程

MERGE INTO 是 SQL 里的"一条语句搞定增删改"操作,也叫 UPSERT(存在则更新,不存在则插入),常用于数据同步、ETL 增量入库。

一、标准语法骨架

复制代码
MERGE INTO 目标表 [AS] t
USING 数据源 [AS] s
  -- 数据源可以是表、视图、子查询、VALUES
ON (t.匹配键 = s.匹配键)
WHEN MATCHED THEN
  UPDATE SET t.col1 = s.col1, t.col2 = s.col2
  -- 可选 WHERE / AND 条件,Oracle 还可加 DELETE WHERE
WHEN NOT MATCHED THEN
  INSERT (col1, col2) VALUES (s.col1, s.col2);
  • MERGE INTO:被修改的表(target)

  • USING:数据来源(source),可以是表也可以是 (SELECT ...) 或 (VALUES ...)

  • ON:只写匹配条件 (如主键相等),不要把常量过滤塞进去,过滤放 WHEN ... AND 里

  • WHEN MATCHED:目标有、源也有 → 更新或删除

  • WHEN NOT MATCHED:源有、目标没有 → 插入

  • 至少要有 1 个 WHEN 分支;SQL Server 必须以分号 ; 结尾

二、最常用:UPSERT(更新或插入)

复制代码
MERGE INTO employees t
USING new_employees s
ON (t.emp_id = s.emp_id)
WHEN MATCHED THEN
  UPDATE SET t.name = s.name,
             t.salary = s.salary,
             t.update_time = CURRENT_TIMESTAMP
WHEN NOT MATCHED THEN
  INSERT (emp_id, name, salary, create_time)
  VALUES (s.emp_id, s.name, s.salary, CURRENT_TIMESTAMP);

效果:工号存在就刷新姓名薪资,不存在就新增。等价于 MySQL 的 INSERT ... ON DUPLICATE KEY UPDATE。

三、带条件更新(避免无变化也写 redo)

Oracle / PostgreSQL / SQL Server 都支持在分支上加 AND:

复制代码
WHEN MATCHED AND s.salary <> t.salary THEN
  UPDATE SET t.salary = s.salary

Oracle 还允许在 UPDATE 后直接跟 WHERE:

复制代码
WHEN MATCHED THEN
  UPDATE SET t.price = s.price
  WHERE t.price <> s.price
  DELETE WHERE s.discontinued = 'Y';   -- 匹配上且满足条件则删

注意:Oracle 里 ON 条件用到的列不能在 UPDATE SET 里改,否则报 ORA-38104。

四、源是子查询 / VALUES(不用建临时表)

PostgreSQL 单行 upsert:

复制代码
MERGE INTO users t
USING (VALUES ('u1001', 'Alice', 28)) AS s(id, name, age)
ON t.id = s.id
WHEN MATCHED THEN UPDATE SET name = s.name, age = s.age
WHEN NOT MATCHED THEN INSERT (id, name, age) VALUES (s.id, s.name, s.age);

五、删除"目标有、源没有"的脏数据

SQL Server / PostgreSQL 17+ / Delta Lake 支持 WHEN NOT MATCHED BY SOURCE:

复制代码
MERGE INTO employees t
USING new_employees s
ON t.emp_id = s.emp_id
WHEN MATCHED THEN
  UPDATE SET t.salary = s.salary
WHEN NOT MATCHED THEN
  INSERT (emp_id, name, salary) VALUES (s.emp_id, s.name, s.salary)
WHEN NOT MATCHED BY SOURCE THEN
  DELETE;   -- 源里没这条工号,目标里删掉

六、各数据库支持情况

数据库 支持度 备注
Oracle 9i+ ✅ 最老牌,DELETE WHERE 是扩展
SQL Server 2008+ ✅ 语句结尾必须 ;;历史版本有已知 bug,高并发建议评估
PostgreSQL 15+ ✅ 17+ 才支持 WHEN NOT MATCHED BY SOURCE
MySQL ❌ 用 INSERT ... ON DUPLICATE KEY UPDATE 或 REPLACE
SQLite 3.24+ ✅ 语法接近标准
Spark / Delta / MaxCompute ✅ 数据仓库场景常用

七、常见踩坑

  1. ON 里只写"怎么算同一条",别写业务过滤 (如 AND status='A' 应挪到 WHEN MATCHED AND status='A'),否则匹配集错乱。

  2. 源数据有重复键 ​ → 同一目标行被匹配两次,SQL Server / Oracle 直接报错;MERGE 前先 ROW_NUMBER() 去重。

  3. ON 的键必须有唯一约束(主键/唯一索引),否则"是否存在"语义不成立。

  4. SQL Server 的 MERGE 在触发器、@@ROWCOUNT、并发下有历史坑,超大数据量同步有时分开写 UPDATE + INSERT 更稳。

  5. 一条 MERGE 里同一行不能被又 UPDATE 又 DELETE,分支条件要互斥。


如果你告诉我用的是 Oracle / SQL Server / PostgreSQL / MySQL​ 哪一种,以及是"两表同步"还是"单条记录 upsert",我可以直接给你一段能跑的版本。

相关推荐
瀚高PG实验室8 小时前
瀚高数据库常用系统表查询入门指南(附常用SQL)
数据库·sql·postgresql·瀚高数据库
xiancai_xianyu12 小时前
Text2SQL落地生产库前,SQL要过哪三道闸
前端·数据库·sql·sql注入·text2sql·ai agent开发·企业级ai框架
cc57250265312 小时前
2027校招准备:数据科学与大数据技术专业转产品数据运营,PRD与SQL怎么安排?
大数据·sql·墨刀
l1t13 小时前
DeepSeek总结的 DuckDB 2.0 中更简洁的变量语法
数据库·sql
l1t16 小时前
DeepSeek总结的在 NVIDIA Vera 上对 DuckDB v2.0-dev 进行基准测试
服务器·数据库·sql
张张123y16 小时前
# 后端第八课:数据库入门(给 FastAPI 接口加上“记忆“,存下问答历史)
数据库·sql·mysql·oracle·fastapi·sqllite
刘胡子大叔19 小时前
旧 SQL 在新 PG 上能不能跑
数据库·sql
软件交付观察室20 小时前
数据大屏总数与明细为什么对不上?2026项目开发排查指南
软件测试·数据库·sql·sqlite·数据可视化
the局外人21 小时前
学会 SQLAlchemy 搭建 Python 与 MySQL 之间的数据访问桥梁 🚀
后端·python·sql
冰暮流星21 小时前
mysql索引失效的情形
数据库·笔记·sql·mysql