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);
复制代码
相关推荐
fen_fen1 天前
Oracle建表语句示例
数据库·oracle
砚边数影1 天前
数据可视化入门:Matplotlib 基础语法与折线图绘制
数据库·信息可视化·matplotlib·数据可视化·kingbase·数据库平替用金仓·金仓数据库
orange_tt1 天前
Djiango配置Celery
数据库·sqlite
云小逸1 天前
【nmap源码学习】 Nmap网络扫描工具深度解析:从基础参数到核心扫描逻辑
网络·数据库·学习
肉包_5111 天前
两个数据库互锁,用全局变量互锁会偶发软件卡死
开发语言·数据库·c++
霖霖总总1 天前
[小技巧64]深入解析 MySQL InnoDB 的 Checkpoint 机制:原理、类型与调优
数据库·mysql
此刻你1 天前
常用的 SQL 语句
数据库·sql·oracle
それども1 天前
分库分表的事务问题 - 怎么实现事务
java·数据库·mysql
·云扬·1 天前
MySQL Binlog 配置指南与核心作用解析
数据库·mysql·adb
天空属于哈夫克31 天前
Java 版:利用外部群 API 实现自动“技术开课”倒计时提醒
数据库·python·mysql