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);
复制代码
相关推荐
电商API_1800790524713 分钟前
批量获取电商商品数据的主流技术方法全解析
大数据·数据库·人工智能·数据分析·网络爬虫
rgeshfgreh35 分钟前
Python流程控制:从条件到循环实战
前端·数据库·python
煎蛋学姐41 分钟前
SSM校园物品交易系统ua3tg(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·学生管理·ssm 框架·商品信息管理·校园物品交易系统·商品分类
conca1 小时前
Java+MySQL时区难题-Date自动转换String差8小时
数据库·mysql
萧曵 丶1 小时前
Redis 是单线程的吗?
数据库·redis
老邓计算机毕设1 小时前
SSM校园招聘管理系统968b0(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·ssm 框架·校园招聘管理系统·简历投递
Zoey的笔记本1 小时前
敏捷与稳定并行:Scrum看板+BPM工具选型指南
大数据·前端·数据库·python·低代码
晴天¥2 小时前
Oracle DB 的相关管理工具
数据库·oracle
Codeking__2 小时前
Redis的value类型介绍——set
数据库·redis·缓存