SQL Server笔记 -- 第16章:MERGE

从SQL Server 2008开始,可以使用MERGE语句在单个语句中执行插入、更新或删除操作。

MERGE语句允许您将数据源与目标表或视图联接,然后根据该联接的结果对目标执行多个操作。

第16.1节:MERGE用于插入/更新/删除

sql 复制代码
MERGE INTO targetTable
USING sourceTable ON (targetTable.PKID = sourceTable.PKID)
WHEN MATCHED AND (targetTable.PKID > 100) THEN DELETE
WHEN MATCHED AND (targetTable.PKID <= 100) THEN UPDATE
    SET targetTable.ColumnA = sourceTable.ColumnA,
        targetTable.ColumnB = sourceTable.ColumnB
WHEN NOT MATCHED THEN
    INSERT (ColumnA, ColumnB) 
    VALUES (sourceTable.ColumnA, sourceTable.ColumnB);
WHEN NOT MATCHED BY SOURCE THEN DELETE ; --< 必需

描述:

  • MERGE INTO targetTable - 要修改的表
  • USING sourceTable - 数据源(可以是表、视图或表值函数)
  • ON ... - targetTable和sourceTable之间的联接条件。
  • WHEN MATCHED - 找到匹配时要采取的操作
    • AND (targetTable.PKID > 100) - 操作要满足的附加条件
    • THEN DELETE - 从targetTable删除匹配的记录
    • THEN UPDATE - 更新由SET ...指定的匹配记录的列
  • WHEN NOT MATCHED - 在targetTable中未找到匹配时要采取的操作
  • WHEN NOT MATCHED BY SOURCE - 在sourceTable中未找到匹配时要采取的操作

注释:

  • 如果不需要特定操作,则省略该条件,例如删除WHEN NOT MATCHED THEN INSERT将阻止插入记录
  • Merge语句需要终止分号。

限制:

  • WHEN MATCHED不允许INSERT操作
  • UPDATE操作只能更新一行一次。这意味着联接条件必须产生唯一匹配。

第16.2节:使用CTE源进行Merge

sql 复制代码
WITH SourceTableCTE AS (
    SELECT * FROM SourceTable
)
MERGE TargetTable AS target
USING SourceTableCTE AS source
ON (target.PKID = source.PKID)
WHEN MATCHED THEN
    UPDATE SET target.ColumnA = source.ColumnA
WHEN NOT MATCHED THEN
    INSERT (ColumnA) VALUES (Source.ColumnA);

第16.3节:Merge示例 - 同步源表和目标表

为了说明MERGE语句,考虑以下两个表

  • dbo.Product:此表包含有关公司当前销售的产品信息
  • dbo.ProductNew:此表包含有关公司将来将销售的产品信息

以下T-SQL将创建并填充这两个表

sql 复制代码
IF OBJECT_id(N'dbo.Product',N'U') IS NOT NULL 
    DROP TABLE dbo.Product
GO

CREATE TABLE dbo.Product (
    ProductID INT PRIMARY KEY,
    ProductName NVARCHAR(64),
    PRICE MONEY
)

IF OBJECT_id(N'dbo.ProductNew',N'U') IS NOT NULL 
    DROP TABLE dbo.ProductNew
GO

CREATE TABLE dbo.ProductNew (
    ProductID INT PRIMARY KEY,
    ProductName NVARCHAR(64),
    PRICE MONEY
)

INSERT INTO dbo.Product 
VALUES(1,'IPod',300),
      (2,'IPhone',400),
      (3,'ChromeCast',100),
      (4,'raspberry pi',50)

INSERT INTO dbo.ProductNew 
VALUES(1,'Asus Notebook',300),
      (2,'Hp Notebook',400),
      (3,'Dell Notebook',100),
      (4,'raspberry pi',50)

现在,假设我们要将dbo.Product目标表与dbo.ProductNew表同步。此任务的标准如下:

  1. 同时存在于dbo.ProductNew源表和dbo.Product目标表中的产品在dbo.Product目标表中更新为新值。
  2. dbo.ProductNew源表中存在但dob.Product目标表中不存在的任何产品都插入到dbo.Product目标表中。
  3. dbo.Product目标表中存在但dbo.ProductNew源表中不存在的任何产品必须从dbo.Product目标表中删除。

以下是执行此任务的MERGE语句。

sql 复制代码
MERGE dbo.Product AS SourceTbl
USING dbo.ProductNew AS TargetTbl
ON (SourceTbl.ProductID = TargetTbl.ProductID)
WHEN MATCHED AND SourceTbl.ProductName <> TargetTbl.ProductName 
              OR SourceTbl.Price <> TargetTbl.Price THEN
    UPDATE SET SourceTbl.ProductName = TargetTbl.ProductName,
               SourceTbl.Price = TargetTbl.Price
WHEN NOT MATCHED THEN
    INSERT (ProductID, ProductName, Price)
    VALUES (TargetTbl.ProductID, TargetTbl.ProductName, TargetTbl.Price)
WHEN NOT MATCHED BY SOURCE THEN
    DELETE
OUTPUT $action, INSERTED.*, DELETED.*;

注意:MERGE语句末尾必须有分号。

第16.4节:使用派生源表进行MERGE

sql 复制代码
MERGE INTO TargetTable AS Target
USING (VALUES (1,'Value1'), (2, 'Value2'), (3,'Value3')) 
      AS Source (PKID, ColumnA)
ON Target.PKID = Source.PKID
WHEN MATCHED THEN
    UPDATE SET target.ColumnA = source.ColumnA
WHEN NOT MATCHED THEN
    INSERT (PKID, ColumnA) 
    VALUES (Source.PKID, Source.ColumnA);

第16.5节:使用EXCEPT进行Merge

使用EXCEPT防止更新未更改的记录

sql 复制代码
MERGE TargetTable targ
USING SourceTable AS src
ON src.id = targ.id
WHEN MATCHED AND EXISTS (
    SELECT src.field
    EXCEPT
    SELECT targ.field
) THEN
    UPDATE SET field = src.field
WHEN NOT MATCHED BY TARGET THEN
    INSERT (id, field)
    VALUES (src.id, src.field)
WHEN NOT MATCHED BY SOURCE THEN
    DELETE;
相关推荐
码上解惑4 分钟前
从 Dify 工作流说起:常用节点怎么选、怎样组合?
java·人工智能·ai·agent·dify·智能体·spring ai
殷忆枫12 分钟前
AI笔记三十七:AI边缘端道桥安全监测系统:YOLOv8n推理与Web监控全解析
笔记·yolo
逸模1 小时前
轻加盟模式,稳住品牌统一调性的思路
笔记·建模·公装·翻模·交底
青山木1 小时前
Hot 100 --- 岛屿数量
java·数据结构·算法·leetcode·深度优先·广度优先
程序员-珍1 小时前
报错下载android sdk失败
android·java
糖果店的幽灵1 小时前
langgraph分支之 - 动态分支(Dynamic Branch)
java·前端·javascript·人工智能·langgraph
whyTeaFo1 小时前
GAMES101: Lecture 10: Geometry 1 (Introduction) ppt笔记
笔记
吃饱了得干活2 小时前
亿级订单表分库分表设计,从0到1全流程
java·数据库·面试
会飞的小新2 小时前
C 标准库之 <fenv.h> 详解与深度解析
c语言·开发语言·microsoft
唐青枫2 小时前
Java Spring Security 实战详解:从登录认证到 JWT 权限控制
java