从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表同步。此任务的标准如下:
- 同时存在于
dbo.ProductNew源表和dbo.Product目标表中的产品在dbo.Product目标表中更新为新值。 dbo.ProductNew源表中存在但dob.Product目标表中不存在的任何产品都插入到dbo.Product目标表中。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;