常用语法

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. MYSQL this function has none of deterministic no sql ......错误

    This function has none of DETERMINISTIC, NO SQL解决办法 创建存储过程时 出错信息: ERROR 1418 (HY000): This function ...

  2. IIS7内建账号,应用程序池

    在IIS7以前的IIS版本中有一个本地帐号,是在安装时创建的,叫做 IUSR_MachineName.一旦启用匿名身份认证,这个IUSR_MachineName帐号就是IIS默认使用的身份(ident ...

  3. Window下 Qt 编译MySQL驱动(居然用到了动态库格式转换工具)

    一步步在Window下开发Qt 今天开始安装MySQL,看了些关于MySQL安装的博文,方法大致相同,但是遇到的细节问题各有不同,或者没有讲全面,下面来说说个人的安装过程及遇到的问题. 1.首先下载, ...

  4. Vim 实用技术,第 1 部分: 实用技巧(转)

    原文链接:http://blog.jobbole.com/20604/ 0. Vim 简介 作为开源世界最重要的编辑器之一(另一个是 Emacs),Vim 以其强大的功能和可定制能力被众多开发者所喜爱 ...

  5. Thread’s start method and run method

    工作中用到了Thread,一开始用错了,仔细研究了一下,稍作整理. 前言,今天写代码居然这样写的 new Thread() { @Override public void run() { System ...

  6. linux之iptable

    转自:http://seanlook.com/2014/02/23/iptables-understand/ 一. netfilter与iptables Netfilter是由Rusty Russel ...

  7. jQuery的hover()方法(笔记)

    因为mouseover和mouseout经常一起写,所以出现了hover() hover(function(){},function(){});第一个参数为鼠标移入运行的函数,第二个为鼠标离开运行的函 ...

  8. eclipse中tomcat启动项目 修改java代码不重启服务

    1.双击tomcat 2.选择modules 3.选中项目点击edit 4.去掉勾.去除auto reloading enabled 的选中 ,点击OK,

  9. BZOJ 2440 完全平方数(莫比乌斯反演+二分查找)

    题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23362 题意:定义含有平方数因子的数为完全平方数(平方数因子不包含 ...

  10. Linux 网络编程: xinetd time

    前言 终于把 xinetd 服务装好了,那就在来实现一下 TCP 协议从服务器和本机获取时间吧.那么多思想汇报还没写,我也是醉了. 安装 xinetd apt-get install xinetd 配 ...