读书笔记之MERGE 语句使用
常用语法
MERGE INTO <target table> AS TGT
USING <SOURCE TABLE> AS SRC
ON <merge predicate>
WHEN MATCHED [AND <predicate>] -- 允许两个子句:
THEN <action> -- UPDATE 和 DELETE
WHEN NOT MATCHED [BY TARGET] [AND <predicate>] -- 允许一个子句:
THEN INSERT... –- INSERT
WHEN NOT MATCHED BY SOURCE [AND <predicate>] -- 允许两个子句:
THEN <action>; -- UPDATE 和 DELETE
建立目标表
-- clear table and reset sequence if the already exist
--TRUNCATE TABLE Sales.MyOrders;
--ALTER SEQUENCE Sales.SeqOrderIDs RESTART WITH 1; -- create table and sequence if they don't already exist
IF OBJECT_ID(N'Sales.MyOrders', N'U') IS NOT NULL DROP TABLE Sales.MyOrders;
IF OBJECT_ID(N'Sales.SeqOrderIDs', N'SO') IS NOT NULL DROP SEQUENCE Sales.SeqOrderIDs; CREATE SEQUENCE Sales.SeqOrderIDs AS INT
MINVALUE 1
CYCLE; CREATE TABLE Sales.MyOrders
(
orderid INT NOT NULL
CONSTRAINT PK_MyOrders_orderid PRIMARY KEY
CONSTRAINT DFT_MyOrders_orderid
DEFAULT(NEXT VALUE FOR Sales.SeqOrderIDs),
custid INT NOT NULL
CONSTRAINT CHK_MyOrders_custid CHECK(custid > 0),
empid INT NOT NULL
CONSTRAINT CHK_MyOrders_empid CHECK(empid > 0),
orderdate DATE NOT NULL
);
源表例子,这里使用参数作为数据源。
-- SELECT without FROM
DECLARE
@orderid AS INT = 1,
@custid AS INT = 1,
@empid AS INT = 2,
@orderdate AS DATE = ''; SELECT *
FROM (SELECT @orderid, @custid, @empid, @orderdate )
AS SRC( orderid, custid, empid, orderdate );
GO -- table value constructor
DECLARE
@orderid AS INT = 1,
@custid AS INT = 1,
@empid AS INT = 2,
@orderdate AS DATE = ''; SELECT *
FROM (VALUES(@orderid, @custid, @empid, @orderdate))
AS SRC( orderid, custid, empid, orderdate);
实际例子
例1 ,很多人用下面这段来更新仓库中的表 (更新存在的,插入不存在的)
-- update where exists (only if different), insert where not exists,
-- delete when exists in target but not in source
DECLARE
@orderid AS INT = 1,
@custid AS INT = 1,
@empid AS INT = 2,
@orderdate AS DATE = ''; MERGE INTO Sales.MyOrders WITH (HOLDLOCK) AS TGT --这里 HOLDLOCK或者SERIALIZABLE作用都是一样的,防止MERGE冲突
USING (VALUES(@orderid, @custid, @empid, @orderdate)) --比如某个主键ID不存在于目标表。有两个进程P1和P2使用MERGE同时处理这个ID
AS SRC( orderid, custid, empid, orderdate) --P1插入了这个ID的同时,P2也插入该ID,此时P2就会因违背主键约束而失败。
ON SRC.orderid = TGT.orderid
--WHEN MATCHED THEN UPDATE --这里有一个性能问题,如果第二次执行该语句,碰到ID一模一样数据,会再一次更新。
WHEN MATCHED AND ( TGT.custid <> SRC.custid --这样会损耗性能,可以额外加判断来减少性能损失。
OR TGT.empid <> SRC.empid
OR TGT.orderdate <> SRC.orderdate) THEN UPDATE
SET TGT.custid = SRC.custid,
TGT.empid = SRC.empid,
TGT.orderdate = SRC.orderdate
WHEN NOT MATCHED THEN INSERT --如果目标表不存在则插入
VALUES(SRC.orderid, SRC.custid, SRC.empid, SRC.orderdate);
WHEN NOT MATCHED BY SOURCE THEN --如果目标表存在但源表不存在则删除
DELETE;
OUTPUT
$action AS the_action,
COALESCE(inserted.orderid, deleted.orderid) AS orderid
注意,有时候还需要处理NULL值
TGT.custid = SRC.custid OR (TGT.custid IS NULL AND SRC.custid IS NOT
NULL) OR (TGT.custid IS NOT NULL AND SRC.custid IS NULL).
例2 ,注意ON 子句规则
MERGE INTO Sales.MyOrders AS TGT
USING Sales.Orders AS SRC
ON SRC.orderid = TGT.orderid
AND shipcountry = N'Norway'
WHEN MATCHED AND ( TGT.custid <> SRC.custid
OR TGT.empid <> SRC.empid
OR TGT.orderdate <> SRC.orderdate) THEN UPDATE
SET TGT.custid = SRC.custid,
TGT.empid = SRC.empid,
TGT.orderdate = SRC.orderdate
WHEN NOT MATCHED THEN INSERT
VALUES(SRC.orderid, SRC.custid, SRC.empid, SRC.orderdate);
以上代码, ON子句有一个谓语 shipcountry = N'Norway' ,当第一次顺利执行。但是第二次就会报错。

之所以报错,是因为ON字句并不会过滤数据,如果shipcountry 不是Norway,则直接执行 NOT MATCHED ,此时因为目标表里面已经有了数据,导致了主键约束错误
解决方法只能事先过滤,然后再执行MERGE
-- 使用CTE
WITH SRC AS
(
SELECT *
FROM Sales.Orders
WHERE shipcountry = N'Norway'
)
MERGE INTO Sales.MyOrders AS TGT
USING SRC
ON SRC.orderid = TGT.orderid
WHEN MATCHED AND ( TGT.custid <> SRC.custid
OR TGT.empid <> SRC.empid
OR TGT.orderdate <> SRC.orderdate) THEN UPDATE
SET TGT.custid = SRC.custid,
TGT.empid = SRC.empid,
TGT.orderdate = SRC.orderdate
WHEN NOT MATCHED THEN INSERT
VALUES(SRC.orderid, SRC.custid, SRC.empid, SRC.orderdate); -- 使用派生表
MERGE INTO Sales.MyOrders AS TGT
USING ( SELECT *
FROM Sales.Orders
WHERE shipcountry = N'Norway' )
AS SRC
ON SRC.orderid = TGT.orderid
WHEN MATCHED AND ( TGT.custid <> SRC.custid
OR TGT.empid <> SRC.empid
OR TGT.orderdate <> SRC.orderdate) THEN UPDATE
SET TGT.custid = SRC.custid,
TGT.empid = SRC.empid,
TGT.orderdate = SRC.orderdate
WHEN NOT MATCHED THEN INSERT
VALUES(SRC.orderid, SRC.custid, SRC.empid, SRC.orderdate);
例3 XML处理
SELECT ProductID ,
Name
INTO Products
FROM Production.Product SELECT ProductID AS "@id" ,
Name AS "@name"
FROM Products
WHERE Name LIKE '_A%'
FOR XML PATH('product') ,
ROOT('products'); DECLARE @Xml XML = N'
<products>
<product id="843" name="Cable Lock" />
<product id="873" name="Patch Kit/8 P11atches" />
<product id="875" delete="true" name="Racing Socks, L" />
<product id="874" name="Racing Socks, M" />
<product id="846" name="Taillights - Battery-Pow1ered" />
<product name="Wdsfe - 30 oz." />
</products>';
WITH src
AS ( SELECT xt.xc.value('@id', 'INT') AS ProductID ,
xt.xc.value('@name', 'NVARCHAR(1000)') AS Name ,
ISNULL(xt.xc.value('@delete', 'BIT'), 0) AS DoDelete
FROM @Xml.nodes('/products/product') AS xt ( xc )
)
MERGE INTO Products AS dest
USING src
ON src.ProductID = dest.ProductID
WHEN NOT MATCHED THEN
INSERT ( Name )
VALUES ( src.Name )
WHEN MATCHED AND src.DoDelete = 0 THEN
UPDATE SET
Name = src.Name
WHEN MATCHED AND src.DoDelete = 1 THEN
DELETE ;
读书笔记之MERGE 语句使用的更多相关文章
- 《C++ Primer Plus》读书笔记之四—分支语句和逻辑操作符
第六章 分支语句和逻辑操作符 1.&&的优先级低于关系操作符. 2.取值范围:取值范围的每一部分都使用AND操作符将两个完整的关系表达式组合起来: if(age>17&& ...
- PHP读书笔记(5)-结构语句
PHP结构语句 顺序结构 顺序结构就像一条直线,按着顺序一直往下执行.我们编写的代码默认都是按照顺序结构执行的. 条件结构之if…else… 条件结构就像一个岔路口,可以向左走,也可以向右走.比如上洗 ...
- 【MySQL 读书笔记】当我们在执行该查询语句的时候我们在干什么
看了非常多 MySQL 相关的书籍和文章,没有看到过如此优秀的专栏.所以未来一段时间我会梳理读完该专栏的所学所得. 当我们在执行该查询语句的时候我们在干什么 mysql> select * fr ...
- 【SQL Server学习笔记】Delete 语句、Output 子句、Merge语句
原文:[SQL Server学习笔记]Delete 语句.Output 子句.Merge语句 DELETE语句 --建表 select * into distribution from sys.obj ...
- 读书笔记系列01-《收获、不止Oracle》
读书笔记系列01-<收获.不止Oracle> 最近计划将看过的Oracle书籍依次系统的总结下读书笔记. 这本书是我个人觉得写的最有趣的Oracle书籍,也是我接触Oracle后第一本完全 ...
- MySQL性能优化总结___本文乃《MySQL性能调优与架构设计》读书笔记!
一.MySQL的主要适用场景 1.Web网站系统 2.日志记录系统 3.数据仓库系统 4.嵌入式系统 二.MySQL架构图: 三.MySQL存储引擎概述 1)MyISAM存储引擎 MyISAM存储引擎 ...
- 【MySQL 读书笔记】普通索引和唯一索引应该怎么选择
通常我们在做这个选择的时候,考虑得最多的应该是如果我们需要让 Database MySQL 来帮助我们从数据库层面过滤掉对应字段的重复数据我们会选择唯一索引,如果没有前者的需求,一般都会使用普通索引. ...
- SQL Server2012 T-SQL基础教程--读书笔记(8 - 10章)
SQL Server2012 T-SQL基础教程--读书笔记(8 - 10章) 示例数据库:点我 CHAPTER 08 数据修改 8.1 插入数据 8.1.1 INSERT VALUES 语句 8.1 ...
- 深入探索Android热修复技术原理读书笔记 —— 代码热修复技术
在前一篇文章 深入探索Android热修复技术原理读书笔记 -- 热修复技术介绍中,对热修复技术进行了介绍,下面将详细介绍其中的代码修复技术. 1 底层热替换原理 在各种 Android 热修复方案中 ...
随机推荐
- 十大最值得注意的MySQL变量
MySQL数据库中的变量非常多,下文为您整理出了十大最值得注意的MySQL变量,希望对您学习MySQL数据库能够有一些帮助. AD: MySQL变量很多,其中有一些MySQL变量非常值得我们注意,下面 ...
- bzoj 2542: [Ctsc2001]终极情报网 费用流
题目链接 2542: [Ctsc2001]终极情报网 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 321 Solved: 125[Submit][S ...
- codeforces 55D. Beautiful numbers 数位dp
题目链接 一个数, 他的所有位上的数都可以被这个数整除, 求出范围内满足条件的数的个数. dp[i][j][k], i表示第i位, j表示前几位的lcm是几, k表示这个数mod2520, 2520是 ...
- poj 2155 matrix 二维线段树
题目链接 区间翻转, 单点查询, 查询操作我真是不太明白...... #include <iostream> #include <vector> #include <cs ...
- JVM内存最大能调多大分析
上次用weblogic 把 -XmxXXXX 设成2G,就启动不起来,设小点就起来了,当时很气,怎么2G都起不了,今天在看到了一篇解释,转过来了这 次一位老友提出了这个问题,记得当年一个java高手在 ...
- Git-常用命令集合
该文章会陆续添加内容,学习网页来自http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 ...
- NYOJ541 最强DE 战斗力(第五届省赛试题)
最强DE 战斗力 时间限制:1000 ms | 内存限制:65535 KB 难度: 描述 春秋战国时期,赵国地大物博,资源非常丰富,人民安居乐业.但许多国家对它虎视眈眈,准备联合起来对赵国发起一场 ...
- PHPRPC for PHP
14的路 PHPRPC for PHP PHPRPC 是一个轻型的.安全的.跨网际的.跨语言的.跨平台的.跨环境的.跨域的.支持复杂对象传输的.支持引用参数传递的.支持内容输出重定向的.支持分级错误处 ...
- C++ signal的使用
1.头文件 #include <signal.h> 2.功能 设置某一信号的对应动作 3.函数原型 typdef void (*sighandler_t )(int); sighan ...
- BootStrap 智能表单系列 二 BootStrap支持的类型简介
代码如下(链接地址:https://github.com/xiexingen/Bootstrap-SmartForm/blob/master/demo/form1-basic.html): <! ...