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);
复制代码
相关推荐
未来之窗软件服务2 小时前
幽冥大陆(六十二) 多数据库交叉链接系统Go语言—东方仙盟筑基期
数据库·人工智能·oracle·golang·数据库集群·仙盟创梦ide·东方仙盟
U-52184F692 小时前
【CGAL实战】深入理解二维受约束 Delaunay 网格生成
数据库·算法
rannn_1112 小时前
【SQL题解】力扣高频 SQL 50题|DAY4
数据库·后端·sql·leetcode·题解
q行2 小时前
MySQL学习日志--DQL和它的七大字句
数据库·学习·mysql
张人玉2 小时前
WPF HTTPS 通信示例使用说明
数据库·网络协议·http·c#·wpf
长春小霸王2 小时前
labview sqlite增删改查
数据库·sqlite·labview
猿小喵2 小时前
记录一次TDSQL-MySQL数据库主从延迟导致批量报错
数据库·mysql
科技块儿2 小时前
【深度解析】在响应速度与数据安全上权衡在线IP查询API与本地IP离线库
数据库·网络协议·tcp/ip
别多香了2 小时前
MySQL 部署安装与核心板块
数据库·mysql