`
kumcun
  • 浏览: 88237 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Merge语句

阅读更多

 把数据从一个表复制到另一个表,插入新数据或替换掉老数据是每一个ORACLE DBA都会经常碰到的问题。在ORACLE9i以前的年代,我们要先查找是否存在老数据,如果有用UPDATE替换,否则用INSERT语句插入,其间少不了还有一些标记变量等等,繁琐的很。现在ORACLE9i专为这种情况提供了MERGE语句,使这一工作变得异常轻松。MERGE语句的语法如下:
 
MERGE [hint] INTO [schema .] table [t_alias]
USING [schema .] { table | view | subquery } [t_alias]
ON ( condition )
WHEN MATCHED THEN merge_update_clause
WHEN NOT MATCHED THEN merge_insert_clause;
 
例如:
MERGE INTO tdest d
USING tsrc s
ON (s.srckey = d.destkey)
WHEN MATCHED THEN UPDATE SET d.destdata = d.destdata + s.srcdata
WHEN NOT MATCHED THEN INSERT (destkey,destdata) VALUES (srckey,srcdata) 一条语句代替了原来的一段复杂语句
 
在Oracle 10g中MERGE有如下一些改进:

 

1、UPDATE或INSERT子句是可选的

 

2、UPDATE和INSERT子句可以加WHERE子句

 

3、在ON条件中使用常量过滤谓词来insert所有的行到目标表中,不需要连接源表和目标表

 

4、UPDATE子句后面可以跟DELETE子句来去除一些不需要的行

 

首先创建示例表:

 

      Create table PRODUCTS      (
      PRODUCT_ID INTEGER,
      PRODUCT_NAME VARCHAR2(60),
      CATEGORY VARCHAR2(60)      );

      insert into PRODUCTS values (1501, 'VIVITAR35 MM', 'ELECTRNCS');
      insert into PRODUCTS values (1502, 'OLYMPUS IS50', 'ELECTRNCS');
      insert into PRODUCTS values (1600, 'PLAY GYM', 'TOYS');
      insert into PRODUCTS values (1601, 'LAMAZE', 'TOYS');
      insert into PRODUCTS values (1666, 'HARRY POTTER', 'DVD');
      commit;

      Create table NEWPRODUCTS      (
      PRODUCT_ID INTEGER,
      PRODUCT_NAME VARCHAR2(60),
      CATEGORY VARCHAR2(60)      );

      insert into NEWPRODUCTS values (1502, 'OLYMPUS CAMERA', 'ELECTRNCS');
      insert into NEWPRODUCTS values (1601, 'LAMAZE', 'TOYS');
      insert into NEWPRODUCTS values (1666, 'HARRY POTTER', 'TOYS');
      insert into NEWPRODUCTS values (1700, 'WAIT INTERFACE', 'BOOKS');
      commit;

 

1、可省略的UPDATE或INSERT子句

 

在Oracle 9i, MERGE语句要求你必须同时指定INSERT和UPDATE子句.而在Oracle 10g, 你可以省略UPDATE或INSERT子句中的一个. 下面的例子根据表NEWPRODUCTS的PRODUCT_ID字段是否匹配来updates表PRODUCTS的信息:

 

SQL> MERGE INTO products p
      2 USING newproducts np
      3 ON (p.product_id = np.product_id)
      4 WHEN MATCHED THEN
      5 UPDATE
      6 SET p.product_name = np.product_name,
      7 p.category = np.category;
      3 rows merged.      

SQL> SELECT * FROM products;
      PRODUCT_ID PRODUCT_NAME CATEGORY
      ---------- -------------------- ----------
      1501 VIVITAR 35MM ELECTRNCS
      1502 OLYMPUS CAMERA ELECTRNCS
      1600 PLAY GYM TOYS
      1601 LAMAZE TOYS
      1666 HARRY POTTER TOYS      

SQL> ROLLBACK;
      Rollback complete.

 

 

 

在上面例子中, MERGE语句影响到是产品id为1502, 1601和1666的行. 它们的产品名字和种类被更新为表newproducts中的值. 下面例子省略UPDATE子句, 把表NEWPRODUCTS中新的PRODUCT_ID插入到表PRODUCTS中, 对于在两个表中能够匹配上PRODUCT_ID的数据不作任何处理. 从这个例子你能看到PRODUCT_ID=1700的行被插入到表PRODUCTS中.

 

SQL> MERGE INTO products p
      2 USING newproducts np
      3 ON (p.product_id = np.product_id)
      4 WHEN NOT MATCHED THEN
      5 INSERT
      6 VALUES (np.product_id, np.product_name,
      7 np.category);
      1 row merged.

SQL> SELECT * FROM products;
      PRODUCT_ID PRODUCT_NAME CATEGORY
      ---------- -------------------- ----------
      1501 VIVITAR 35MM ELECTRNCS
      1502 OLYMPUS IS50 ELECTRNCS
      1600 PLAY GYM TOYS
      1601 LAMAZE TOYS
      1666 HARRY POTTER DVD
      1700 WAIT INTERFACE BOOKS

  

2、带条件的Updates和Inserts子句

 

你能够添加WHERE子句到UPDATE或INSERT子句中去, 来跳过update或insert操作对某些行的处理. 下面例子根据表NEWPRODUCTS来更新表PRODUCTS数据, 但必须字段CATEGORY也得同时匹配上:

 

SQL> MERGE INTO products p
      2 USING newproducts np
      3 ON (p.product_id = np.product_id)
      4 WHEN MATCHED THEN
      5 UPDATE
      6 SET p.product_name = np.product_name
      7 WHERE p.category = np.category;
      2 rows merged.

SQL> SELECT * FROM products;
      PRODUCT_ID PRODUCT_NAME CATEGORY
      ---------- -------------------- ----------
      1501 VIVITAR 35MM ELECTRNCS
      1502 OLYMPUS CAMERA ELECTRNCS
      1600 PLAY GYM TOYS
      1601 LAMAZE TOYS
      1666 HARRY POTTER DVD

SQL> rollback;

 

在这个例子中, 产品ID为1502,1601和1666匹配ON条件但是1666的category不匹配. 因此MERGE命令只更新两行数据. 下面例子展示了在Updates和Inserts子句都使用WHERE子句:

 

 

SQL> MERGE INTO products p
      2 USING newproducts np
      3 ON (p.product_id = np.product_id)
      4 WHEN MATCHED THEN
      5 UPDATE
      6 SET p.product_name = np.product_name,
      7 p.category = np.category
      8 WHERE p.category = 'DVD'
      9 WHEN NOT MATCHED THEN
      10 INSERT
      11 VALUES (np.product_id, np.product_name, np.category)
      12 WHERE np.category != 'BOOKS';
      1 row merged.

SQL> SELECT * FROM products;
      PRODUCT_ID PRODUCT_NAME CATEGORY
      ---------- -------------------- ----------
      1501 VIVITAR 35MM ELECTRNCS
      1502 OLYMPUS IS50 ELECTRNCS
      1600 PLAY GYM TOYS
      1601 LAMAZE TOYS
      1666 HARRY POTTER TOYS

 

 

 

注意由于有WHERE子句INSERT没有插入所有不匹配ON条件的行到表PRODUCTS.

3、无条件的Inserts

 

你能够不用连接源表和目标表就把源表的数据插入到目标表中. 这对于你想插入所有行到目标表时是非常有用的. Oracle 10g现在支持在ON条件中使用常量过滤谓词. 举个常量过滤谓词例子ON (1=0). 下面例子从源表插入行到表PRODUCTS, 不检查这些行是否在表PRODUCTS中存在:

 

SQL> MERGE INTO products p
      2 USING newproducts np
      3 ON (1=0)
      4 WHEN NOT MATCHED THEN
      5 INSERT
      6 VALUES (np.product_id, np.product_name, np.category)
      7 WHERE np.category = 'BOOKS';
      1 row merged.
      
SQL> SELECT * FROM products;
      PRODUCT_ID PRODUCT_NAME CATEGORY
      ---------- -------------------- ----------
      1501 VIVITAR 35MM ELECTRNCS
      1502 OLYMPUS IS50 ELECTRNCS
      1600 PLAY GYM TOYS
      1601 LAMAZE TOYS
      1666 HARRY POTTER DVD
      1700 WAIT INTERFACE BOOKS
      6 rows selected.

 

 

 

4、新增加的DELETE子句

 

Oracle 10g中的MERGE提供了在执行数据操作时清除行的选项. 你能够在WHEN MATCHED THEN UPDATE子句中包含DELETE子句. DELETE子句必须有一个WHERE条件来删除匹配某些条件的行.匹配DELETE WHERE条件但不匹配ON条件的行不会被从表中删除.

 

下面例子验证DELETE子句. 我们从表NEWPRODUCTS中合并行到表PRODUCTS中, 但删除category为ELECTRNCS的行.

 

 

SQL> MERGE INTO products p
      2 USING newproducts np
      3 ON (p.product_id = np.product_id)
      4 WHEN MATCHED THEN
      5 UPDATE
      6 SET p.product_name = np.product_name,
      7 p.category = np.category
      8 DELETE WHERE (p.category = 'ELECTRNCS')
      9 WHEN NOT MATCHED THEN 
     10 INSERT 
     11 VALUES (np.product_id, np.product_name, np.category);
      4 rows merged.
      
SQL> SELECT * FROM products;
      PRODUCT_ID PRODUCT_NAME CATEGORY
      ---------- -------------------- ----------
      1501 VIVITAR 35MM ELECTRNCS
      1600 PLAY GYM TOYS
      1601 LAMAZE TOYS
      1666 HARRY POTTER TOYS
      1700 WAIT INTERFACE BOOKS

 

产品ID为1502的行从表PRODUCTS中被删除, 因为它同时匹配ON条件和DELETE WHERE条件. 产品ID为1501的行匹配DELETE WHERE条件但不匹配ON条件, 所以它没有被删除. 产品ID为1700 的行不匹配ON条件, 所以被插入表PRODUCTS. 产品ID为1601和1666的行匹配ON条件但不匹配DELETE WHERE条件, 所以被更新为表NEWPRODUCTS中的值.

 

 

 

 

 

 

 

 ---------------------------------- =====Line===== ----------------------------------

 

设计技巧 #107 使用MERGE语句进行渐变维处理

 

 

 

 

 

November 6, 2008

 

作者:Warren Thornthwaite

译者:Daniel Zhen

 

很多ETL工具都提供了处理渐变维度的功能。也有些情况下,当此类工具不能满足需求时,ETL开发者将直接面对数据库,验证更新或变化了的行,并恰当的使用INSERTUPDATE命令处理之。在“深入数据仓库生命周期”课程上,我已经演示了使用INSERTUPDATE语句的代码。几个月后,我的朋友Stuart Ozer告诉我,使用SQL Server 2008中的MERGE语句在代码执行方面有更好的效率。他所引用的是MSSQLTips.comChad BoydBlog,这给了我一些如何实现的启示。MERGEINSERTUPDATEDELETE的组合,它有效的降低了语句的复杂度。

本例处理的是简单的客户维度,它具有两个属性:first namelast name。我们将把first name作为类型1处理,把last name看作类型二处理。记住,所谓类型1是指维度属性的旧值覆写;类型二是通过增加新值让跟踪历史纪录更具效率。

 

步骤 1: 覆写类型1中的变化值

我曾尝试在整个例子中只使用一次MERGE语句,但该函数属于确定性函数,每次只能执行一次update语句,所以我在下例中分别使用了多个MERGE进行类型1更新。因为类型1定义为更新,所以也可以使用update语句直接处理。

 

MERGE INTO dbo.Customer_Master AS CM

USING Customer_Source AS CS

ON (CM.Source_Cust_ID = CS.Source_Cust_ID)

WHEN MATCHED AND --根据类型1更新所有已存在的行

CM.First_Name <> CS.First_Name

THEN UPDATE SET CM.First_Name = CS.First_Name

 

以上简版的MERGE语句,通过关联业务键,更新所有主表和原表中First_Name不一致的行,实现了Customer_Source表和Customer_Master维度的归并。

 

步骤 2: 处理类型2中的变化值

现在我们将使用另一个MERGE语句来处理类型2中的变化值。这是件比较棘手的事,因为在跟踪类型2变化值是会有很多的步骤。执行我们代码将需要:

 

1. 在截止时间前,适当并有效地插入新客户数据行。

2. 通过设置恰当的终止时间和设置current_row flag = ‘n’,标识类型2中维度属性变化的行。

3. 通过设置恰当的终止时间和设置current_row flag = ‘y’,插入类型2的变化行。

 

这样做会导致太多的步骤需要MERGE处理的问题。幸运的是,MERGE可以流化输出到下一个过程。我们将使用这一功能,使用SELECTMERGE的结果中选择行并插入到Customer_Master表中,最终完成类型2变化行的插入。听上去,这是一种复杂的并容易出问题的方法,但是它的好处在在于可以一次性找到类型2中变化了的行,并可以多次使用。

代码以INSERTSELECT语句开始,用来在MERGE语句执行后处理变化行插入。之所以把它们放在前面,是因为MERGE是包含在INSERT嵌套中的。代码中包含很多对于当前日期的引用,代码中假设变化自昨天起有效(getdate()-1),即前天(getdate()-2)的数据可以被标识为退化。最后,我列出了代码,并根据行号进行说明:

 

1 INSERT INTO Customer_Master

2 SELECT Source_Cust_ID, First_Name, Last_Name, Eff_Date, End_Date, Current_Flag

3 FROM

4 ( MERGE Customer_Master CM

5 USING Customer_Source CS

6 ON (CM.Source_Cust_ID = CS.Source_Cust_ID)

7 WHEN NOT MATCHED THEN

8 INSERT VALUES (CS.Source_Cust_ID, CS.First_Name, CS.Last_Name,

convert(char(10), getdate()-1, 101), '12/31/2199', 'y')

9 WHEN MATCHED AND CM.Current_Flag = 'y'

10 AND (CM.Last_Name <> CS.Last_Name ) THEN

11 UPDATE SET CM.Current_Flag = 'n', CM.End_date = convert(char(10), getdate()-

2, 101)

12 OUTPUT $Action Action_Out, CS.Source_Cust_ID, CS.First_Name, CS.Last_Name,

convert(char(10), getdate()-1, 101) Eff_Date, '12/31/2199' End_Date, 'y'Current_Flag

13 ) AS MERGE_OUT

14 WHERE MERGE_OUT.Action_Out = 'UPDATE';

 

代码注释

Ø  1-3行执行典型的INSERT语句. 将用来在最后插入类型2的变化行。

Ø  4行是MERGE语句的开始,直到第13行。MERGE语句中有OUTPUT标识符,它将流化MERGE的结果,并由函数调用。该语法定义了一般表表达式,这本质上是一个FROM标识符中的临时表,被称作MERGE_OUT

Ø  4-6行执行MERGE,装载Customer_Source数据进入Customer_Master维度表。

Ø  7行说明如果无法匹配业务键,我们必须有一个新的客户数据加入,因此第8行执行了插入操作。你可以通过参数化有效日期取代假设的昨天的日期。

Ø  9-10行定义了业务键可以进行匹配的行的子集,特别是,Customer_Master表中已有数据和类型font-size: 10p

分享到:
评论

相关推荐

    DB2 merge语句使用教程

    DB2 merge语句使用教程

    触发器Merge语句执行.txt

    可通过merge语句功能,进行数据同步存储功能,里面有具体事例可供参考。大大减少了开发时间,提高了工作执行效率。

    解析SQL Server 2008中的新语句:MERGE

    根据一个源数据表对另一个数据表进行确定性的插入、更新和删除这样复杂的操作,运用新的MERGE语句,开发者用一条命令就可以完成。对两个表进行信息同步时,有三步操作要进行。首先要处理任何需要插入目标数据表的新...

    MySQL中实现插入或更新操作(类似Oracle的merge语句)

    主要介绍了在MySQL中实现插入或更新操作(类似Oracle的merge语句)的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下

    使用BULK COLLECT, MERGE 语句提高sql执行效率

    详细介绍了使用 BULK COLLECT 进行批量操作 提高sql的执行效率 使用MERGE INTO USING 一条sql搞定 新增和修改 使用connect by 进行递归树查询

    generate-sql-merge:生成带有表数据SQL MERGE语句

    生成带有表数据SQL MERGE语句 该系统存储过程将表名作为参数,并生成包含所有表数据的MERGE语句。 如果您需要,例如,这很有用。 生成的MERGE语句可以包含在源代码管理中,并用于在DEV / TEST / PROD之间部署数据。...

    DB2 MERGE INTO语句的使用

    DB2中的Merge语句可以将一个表中的数据合并到另一个表中,在合并的同时可以根据条件进行插入、删除、更新等操作,功能非常强大。

    SQL Server使用Merge语句当源表数据集为空时,无法进行查询的问题

    今天使用Merge语句时遇到了一个问题,当源表数据集为空时,merge就不工作了。

    Oracle SQL高级编程(资深Oracle专家力作,OakTable团队推荐)--随书源代码

    1.9 MERGE语句 22 1.10 小结 24 第2章 SQL执行 25 2.1 Oracle架构基础 25 2.2 SGA-共享池 27 2.3 库高速缓存 28 2.4 完全相同的语句 29 2.5 SGA-缓冲区缓存 32 2.6 查询转换 35 2.7 视图合并 36 2.8 子...

    SQLServer 2008 Merge语句的OUTPUT功能

    下面介绍一下把Output同2008的新T-SQL语句Merge组合使用的方法: 新建下面表: 代码如下:CREATE TABLE Book( ISBN varchar(20) PRIMARY KEY, Price decimal, Shelf int) CREATE TABLE WeeklyChange( ISBN varchar(20...

    Merge Into 语句代替InsertUpdate

    非常经典的SQL经验,适合于数据库初学者及长期从事软件开发者

    Merge-Sql.zip

    本文探讨如何在不同的数据库中使用这些MERGE语句。我们将检查其他替代方法,因为所有数据库和版本都不支持MERGE语句。

    SQL中Merge用法详解

    MERGE语句是SQL语句的一种。在SQL Server、Oracle数据库中可用,MySQL、PostgreSQL中不可用。MERGE是Oracle9i新增的语法,用来合并UPDATE和INSERT语句。通过MERGE语句,根据一张表(原数据表,source table)或子...

    mysql面试题,涉及MySQL基础、MySQL索引、MySQL语句 MySQL进阶等方面,适用于初、中级开发人员

    MySQL 中没有类似 Oracle 的 merge 语句,但是可以使用两种方法来实现类似的功能:INSERT INTO … ON DUPLICATE KEY UPDATE 和 REPLACE INTO。前者使用 INSERT 语句向表中插入记录,如果发现主键或唯一键冲突,则...

    Oracle_merge

    在Oracle 9i R2版中引入的MERGE语句通常被称作“更新插入”(upsert),因为使用MERGE可以在同一个步骤中更新(update)并插入(insert)数据行。。。。。。

    merge用法详解

    无论你在使用任何DBMS,你总是难以避免的将会遇到上面提到的这种需求,如果你不使用merge语句,你将会不得不在程序中增加大段的代码,或者是在oracle用很长的代码来实现。好在现在我们有了merge,可以帮我们省下很多...

Global site tag (gtag.js) - Google Analytics