读书笔记之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 热修复方案中 ...
随机推荐
- java Socket 列子 一些参数设置比较全
http://blog.csdn.net/a19881029/article/details/11596945
- URL伪静态设置 (apache2.4)
` ` 1.修改apche主配置文件 主要是 #LoadModule rewrite_module modules/mod_rewrite.so 改为 LoadModule rewrite_modul ...
- [Java]使用队列求解josephus问题
约瑟夫斯问题(有时也称为约瑟夫斯置换),是一个出现在计算机科学和数学中的问题.在计算机编程的算法中,类似问题又称为约瑟夫环. 有个囚犯站成一个圆圈,准备处决.首先从一个人开始,越过个人(因为第一个人已 ...
- 阿里云ECS每天一件事D4:安装mysql5.5.40
Linux平台上MySQL也没什么好说的了,首先准备一下软件环境: yum install gcc gcc-c++ gcc-g77 autoconf automake make cmake bison ...
- 有感于NC的强大
第一次知道nc(netcat)是好几年前的事了,那个时候天比现在更蓝,草比现在更绿,卤煮也还是一个刚上大学不久的青葱骚年... 现在把这个01年的老古董拿出来说好像有点炒冷饭的意思,资料也铺天盖地了说 ...
- 利用svg技术实现在线动画演示
搜索MDCC的论文,发现了这个站点,里面有演示动画,居然是通过svg来实现的. 分享给大家看看: 有空研究下,做一个类似的演示,展示一下OceanBase内部的常见操作. 展示一个svg做的游戏: h ...
- 160G 视频教程(Java+Android+项目视频)免费下载
我不喜欢多说没用,直接给下载链接,进去直接下载,下载不动的联系网站客服解决!我只和我的好朋友们分享好的视频教程 http://edu.csdn.net/main/video.shtml 视频教程目录过 ...
- .Net时间计算函数,统计某一天是一年的第几周,这一周从哪天开始到哪天结束
/// <summary> /// 计算某年第一周的天数 /// </summary> /// <param name="dt& ...
- ANDROID对文件的操作介绍
1. Android遵循MVC设计思想: M(业务层):service V:视图(main.xml). C:Activity 2.使用文件如何对数据进行存储 Activity提供了openFileOu ...
- 火狐浏览器开始支持3D游戏和视屏通话
最近,Mozilla发布了第22版本的火狐浏览器,这个版本增加了对3D游戏.视频通话和文件分享功能的支持.现在使用者不必下载额外的插件或者第三方软件就可以使用上面的所有特性.为了鼓励更多的开发者为火狐 ...