常用语法

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 语句使用的更多相关文章

  1. 《C++ Primer Plus》读书笔记之四—分支语句和逻辑操作符

    第六章 分支语句和逻辑操作符 1.&&的优先级低于关系操作符. 2.取值范围:取值范围的每一部分都使用AND操作符将两个完整的关系表达式组合起来: if(age>17&& ...

  2. PHP读书笔记(5)-结构语句

    PHP结构语句 顺序结构 顺序结构就像一条直线,按着顺序一直往下执行.我们编写的代码默认都是按照顺序结构执行的. 条件结构之if…else… 条件结构就像一个岔路口,可以向左走,也可以向右走.比如上洗 ...

  3. 【MySQL 读书笔记】当我们在执行该查询语句的时候我们在干什么

    看了非常多 MySQL 相关的书籍和文章,没有看到过如此优秀的专栏.所以未来一段时间我会梳理读完该专栏的所学所得. 当我们在执行该查询语句的时候我们在干什么 mysql> select * fr ...

  4. 【SQL Server学习笔记】Delete 语句、Output 子句、Merge语句

    原文:[SQL Server学习笔记]Delete 语句.Output 子句.Merge语句 DELETE语句 --建表 select * into distribution from sys.obj ...

  5. 读书笔记系列01-《收获、不止Oracle》

    读书笔记系列01-<收获.不止Oracle> 最近计划将看过的Oracle书籍依次系统的总结下读书笔记. 这本书是我个人觉得写的最有趣的Oracle书籍,也是我接触Oracle后第一本完全 ...

  6. MySQL性能优化总结___本文乃《MySQL性能调优与架构设计》读书笔记!

    一.MySQL的主要适用场景 1.Web网站系统 2.日志记录系统 3.数据仓库系统 4.嵌入式系统 二.MySQL架构图: 三.MySQL存储引擎概述 1)MyISAM存储引擎 MyISAM存储引擎 ...

  7. 【MySQL 读书笔记】普通索引和唯一索引应该怎么选择

    通常我们在做这个选择的时候,考虑得最多的应该是如果我们需要让 Database MySQL 来帮助我们从数据库层面过滤掉对应字段的重复数据我们会选择唯一索引,如果没有前者的需求,一般都会使用普通索引. ...

  8. SQL Server2012 T-SQL基础教程--读书笔记(8 - 10章)

    SQL Server2012 T-SQL基础教程--读书笔记(8 - 10章) 示例数据库:点我 CHAPTER 08 数据修改 8.1 插入数据 8.1.1 INSERT VALUES 语句 8.1 ...

  9. 深入探索Android热修复技术原理读书笔记 —— 代码热修复技术

    在前一篇文章 深入探索Android热修复技术原理读书笔记 -- 热修复技术介绍中,对热修复技术进行了介绍,下面将详细介绍其中的代码修复技术. 1 底层热替换原理 在各种 Android 热修复方案中 ...

随机推荐

  1. Python3.5创建虚拟环境

    为每个程序单独创建虚拟环境可以保证程序只能访问虚拟环境中的包,保持全局解释器的干净整洁,使其只作为创建(更多)虚拟环境的源. windows下创建虚拟环境 Python3.5自带venv,只需执行py ...

  2. Qt全屏显示窗口、子窗口的相关函数

    Qt全屏显示函数         window.showFullScreen() Qt最大化显示函数         window.showMaximized() Qt最小化显示函数         ...

  3. 《windows程序设计》学习_3.4:实现雷区翻转

    #include<windows.h> #include "resource.h" LRESULT CALLBACK WndProc (HWND, UINT, WPAR ...

  4. Windows环境下用C#编程将文件上传至阿里云OSS笔记

    Windows环境下用C#编程将文件上传至阿里云OSS笔记 本系列文章由ex_net(张建波)编写,转载请注明出处. http://blog.csdn.net/ex_net/article/detai ...

  5. CSS 布局总结——固定宽度布局

    固定宽度布局 单列布局 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2Fyd29sZjI0/font/5a6L5L2T/fontsize/400/fil ...

  6. Android Intent的几种使用方法全面总结

    Intent应该算是Android中特有的东西.你能够在Intent中指定程序要运行的动作(比方:view,edit,dial),以及程序运行到该动作时所须要的资料.都指定好后,仅仅要调用startA ...

  7. MSSQL常用函数大全

    一.字符转换函数1.ASCII()返回字符表达式最左端字符的ASCII 码值.在ASCII()函数中,纯数字的字符串可不用‘’括起来,但含其它字符的字符串必须用‘’括起来使用,否则会出错. 2.CHA ...

  8. FMDB 直接将查询结果转化为字典

    今天学习FMDB框架,发现非常好用的一点,就是就以把查询结果直接转化为字典 NSString *querySql = @"select * from stuInfo"; NSMut ...

  9. eclipse修改编译路径

    右击项目--properties--java build path--点击source,修改最下方的路径即可

  10. HDU 2087 剪花布条(模式串在主串中出现的次数主串中子串不可重叠)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087 题意:求模式串在主串中出现的次数,与模式串匹配的子串之间不可重叠. 思路:用kmp算法解决,在匹 ...