MERGE INTO语句

MERGE INTO 是什么?

MERGE INTO(在 Oracle 中)也称为 UPSERT,它将 INSERT、UPDATE 和 DELETE 操作合并到一个语句中

基本语法结构:

复制代码
MERGE INTO 目标表
USING 源数据
ON (连接条件)
WHEN MATCHED THEN      -- 当匹配时(记录存在)
    UPDATE SET ...     -- 执行更新
    [DELETE WHERE ...] -- 可选:删除条件
WHEN NOT MATCHED THEN  -- 当不匹配时(记录不存在)
    INSERT (...)       -- 执行插入
    VALUES (...);

类比理解

想象成两个 Excel 表格的操作:

步骤 类比 Excel 操作
MERGE INTO 目标表格(要更新的表)
USING 源表格(提供数据的表)
ON 用哪一列匹配两个表格
WHEN MATCHED 如果找到相同的行
WHEN NOT MATCHED 如果没找到相同的行

MERGE 关键要点总结:

  1. MERGE INTO + 目标表

  2. USING + 源数据(表或子查询)

  3. ON + 匹配条件(像 JOIN)

  4. WHEN MATCHED + 更新操作

  5. WHEN NOT MATCHED + 插入操作(可选)

为什么用 MERGE 而不是 UPDATE?

使用 MERGE 的优势:

  1. 一次操作,多种处理:可以同时处理存在和不存在的情况

  2. 性能更好:避免先查询再更新的两次操作

  3. 原子性:要么全部成功,要么全部失败

  4. 避免重复代码

MERGE INTO 使用案例

案例1:最简单的 MERGE - 员工薪资同步

sql 复制代码
-- 场景:用新员工表同步更新员工表
MERGE INTO employees target
USING new_employees source
ON (target.emp_id = source.emp_id)
WHEN MATCHED THEN
    UPDATE SET 
        target.salary = source.salary,
        target.department = source.department
WHEN NOT MATCHED THEN
    INSERT (emp_id, name, salary, department)
    VALUES (source.emp_id, source.name, source.salary, source.department);

案例2:商品价格同步 - 根据来源更新

sql 复制代码
-- 场景:根据不同供应商更新商品价格
MERGE INTO product_prices target
USING (
    -- 多个来源的价格数据
    SELECT product_id, supplier_id, price, 'SUPPLIER_A' as source
    FROM supplier_a_prices
    UNION ALL
    SELECT product_id, supplier_id, price, 'SUPPLIER_B' as source
    FROM supplier_b_prices
) source
ON (target.product_id = source.product_id AND target.supplier_id = source.supplier_id)
WHEN MATCHED THEN
    UPDATE SET 
        target.price = source.price,
        target.source = source.source,
        target.update_time = SYSDATE
WHEN NOT MATCHED THEN
    INSERT (product_id, supplier_id, price, source, create_time)
    VALUES (source.product_id, source.supplier_id, source.price, source.source, SYSDATE);

案例3:会员积分更新 - 含条件更新和删除

sql 复制代码
-- 场景:更新会员积分,过期积分删除
MERGE INTO member_points target
USING (
    SELECT member_id, SUM(points) as earn_points
    FROM point_records
    WHERE earn_date >= TRUNC(SYSDATE) - 30  -- 最近30天
    GROUP BY member_id
) source
ON (target.member_id = source.member_id)
WHEN MATCHED THEN
    UPDATE SET 
        target.total_points = target.total_points + source.earn_points,
        target.last_earn_date = SYSDATE
    DELETE WHERE target.expire_date < SYSDATE  -- 删除过期记录
WHEN NOT MATCHED THEN
    INSERT (member_id, total_points, last_earn_date, expire_date)
    VALUES (source.member_id, source.earn_points, SYSDATE, ADD_MONTHS(SYSDATE, 12));

案例4:订单状态同步 - 简化的实际业务场景

sql 复制代码
-- 场景:根据物流单更新订单状态
MERGE INTO orders target
USING logistics source
ON (target.order_no = source.order_no)
WHEN MATCHED THEN
    UPDATE SET 
        target.status = 
            CASE 
                WHEN source.delivery_status = 'DELIVERED' THEN 'COMPLETED'
                WHEN source.delivery_status = 'SHIPPED' THEN 'IN_TRANSIT'
                ELSE target.status
            END,
        target.delivery_time = 
            CASE 
                WHEN source.delivery_status = 'DELIVERED' THEN source.delivery_time
                ELSE target.delivery_time
            END;

案例5:你的业务场景简化版

sql 复制代码
-- 简化你的追踪明细更新
MERGE INTO ct_price_tracking_item target
USING (
    -- 计算接收数量
    SELECT item_id, SUM(receive_qty) as total_received
    FROM receive_records
    WHERE receive_date >= DATE '2024-01-01'
    GROUP BY item_id
) source
ON (target.item_id = source.item_id)
WHEN MATCHED THEN
    UPDATE SET 
        target.receive_qty = source.total_received,
        target.update_time = SYSDATE;
复制代码

练习案例:创建测试表和数据

sql 复制代码
-- 1. 创建目标表
CREATE TABLE products (
    product_id NUMBER PRIMARY KEY,
    product_name VARCHAR2(50),
    price NUMBER(10,2),
    stock_qty NUMBER,
    update_date DATE
);

-- 2. 创建源表
CREATE TABLE price_updates (
    product_id NUMBER,
    new_price NUMBER(10,2),
    update_type VARCHAR2(10)
);

-- 3. 插入测试数据
INSERT INTO products VALUES (1, 'Product A', 100, 50, SYSDATE);
INSERT INTO products VALUES (2, 'Product B', 200, 30, SYSDATE);

INSERT INTO price_updates VALUES (1, 120, 'INCREASE');
INSERT INTO price_updates VALUES (3, 300, 'NEW');

-- 4. 执行 MERGE(练习用)
MERGE INTO products target
USING price_updates source
ON (target.product_id = source.product_id)
WHEN MATCHED THEN
    UPDATE SET 
        target.price = source.new_price,
        target.update_date = SYSDATE
WHEN NOT MATCHED THEN
    INSERT (product_id, product_name, price, stock_qty, update_date)
    VALUES (source.product_id, 'New Product', source.new_price, 0, SYSDATE);
复制代码
相关推荐
小陈工7 小时前
Python Web开发入门(十七):Vue.js与Python后端集成——让前后端真正“握手言和“
开发语言·前端·javascript·数据库·vue.js·人工智能·python
科技小花12 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸12 小时前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain12 小时前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希13 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神13 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员13 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java13 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿13 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb
不知名的老吴13 小时前
Redis的延迟瓶颈:TCP栈开销无法避免
数据库·redis·缓存