zoukankan      html  css  js  c++  java
  • 使用MERGE语句同步表

    
    先建好測试环境:
    
     
    
    USE TEMPDB
    GO
    IF OBJECT_ID('T1') IS NOT NULL DROP TABLE T1
    IF OBJECT_ID('T2') IS NOT NULL DROP TABLE T2
    GO
    CREATE TABLE T1(ID1 INT,VAL1 VARCHAR(50))
    CREATE TABLE T2(ID2 INT,VAL2 VARCHAR(50))
    GO
    INSERT INTO T1
    SELECT 1,'A' UNION ALL
    SELECT 2,'B' UNION ALL
    SELECT 3,'C'
    
     
    
    如今我们的目标是让T2表与T1表同步,我直接把完整的MERGE语句帖上来,等下再细说各个部分:
    MERGE INTO T2 AS TB_TARGET
    USING T1 AS TB_SOURCE
    ON TB_TARGET.ID2=TB_SOURCE.ID1
    WHEN NOT MATCHED BY TARGET THEN 
    INSERT(ID2,VAL2)
    VALUES(ID1,VAL1)
    WHEN NOT MATCHED BY SOURCE THEN
    DELETE
    WHEN MATCHED AND TB_TARGET.VAL2<>TB_SOURCE.VAL1 THEN 
    UPDATE SET
    TB_TARGET.VAL2=TB_SOURCE.VAL1
    OUTPUT $ACTION,ISNULL(DELETED.ID2,INSERTED.ID2) AS ID,DELETED.VAL2,INSERTED.VAL2
    ;
    
    看看MERGE语句输出的结果
    
    /*
    
    $ACTION    ID2         VAL2                                               VAL2
    ---------- ----------- -------------------------------------------------- --------------------------------------------------
    INSERT     1           NULL                                               A
    INSERT     2           NULL                                               B
    INSERT     3           NULL                                               C
    
    */
    
    再看一下如今T2的内容:
    
     
    
    SELECT * FROM T2
    
    /*
    
    ID2         VAL2
    ----------- --------------------------------------------------
    1           A
    2           B
    3           C
    
    */
    
     
    
    能够看到T1的东东已经过去了,也就是说初步的同步完毕了。
    
    如今做一些其他的操作,我们分别插入、更新、删除一条数据:
    
    UPDATE T1 SET VAL1='D' WHERE ID1=3
    
    
    DELETE FROM T1 WHERE ID1=2
    
    
    INSERT INTO T1
    SELECT 4,'E'
    
    
    
    SELECT * FROM T1 
    /*
    ID1         VAL1
    ----------- --------------------------------------------------
    1           A
    4           E
    3           D
    */
    
    如今各种数据都有了,1没变,2删了,3改了,4是加的。再执行上面那坨MERGE语句:
    
    MERGE INTO T2 AS TB_TARGET
    USING T1 AS TB_SOURCE
    ON TB_TARGET.ID2=TB_SOURCE.ID1
    WHEN NOT MATCHED BY TARGET THEN 
    INSERT(ID2,VAL2)
    VALUES(ID1,VAL1)
    WHEN NOT MATCHED BY SOURCE THEN
    DELETE
    WHEN MATCHED AND TB_TARGET.VAL2<>TB_SOURCE.VAL1 THEN 
    UPDATE SET
    TB_TARGET.VAL2=TB_SOURCE.VAL1
    OUTPUT $ACTION,ISNULL(DELETED.ID2,INSERTED.ID2) AS ID,DELETED.VAL2,INSERTED.VAL2
    ;
    
    /*
    
    $ACTION    ID          VAL2                                               VAL2
    ---------- ----------- -------------------------------------------------- --------------------------------------------------
    INSERT     4           NULL                                               E
    DELETE     2           B                                                  NULL
    UPDATE     3           C                                                  D
    
    */
    
     
    
    看一下T2的数据
    
    SELECT * FROM T2
    
    /*
    
    ID2         VAL2
    ----------- --------------------------------------------------
    1           A
    3           D
    4           E
    
    */
    
    能够看到,数据已经全然同步了。看到效果后,我们就能够開始说正文了,我再粘一次MERGE语句,然后一句一句细说
    
    MERGE INTO T2 AS TB_TARGET
    USING T1 AS TB_SOURCE
    ON TB_TARGET.ID2=TB_SOURCE.ID1
    WHEN NOT MATCHED BY TARGET THEN 
    INSERT(ID2,VAL2)
    VALUES(ID1,VAL1)
    WHEN NOT MATCHED BY SOURCE THEN
    DELETE
    WHEN MATCHED AND TB_TARGET.VAL2<>TB_SOURCE.VAL1 THEN 
    UPDATE SET
    TB_TARGET.VAL2=TB_SOURCE.VAL1
    OUTPUT $ACTION,ISNULL(DELETED.ID2,INSERTED.ID2) AS ID,DELETED.VAL2,INSERTED.VAL2
    ;
    
     
    
    1.
    
    MERGE INTO T2 AS TB_TARGET
    
    指定要同步的目标表。MERGE是keyword,INTO可有可无,T2是目标表名,AS可有可无,TB_TARGET是表别名。
    
    假设要对目标表加表提示和索引提示,比方WITH(...),加在T2和AS中间就能够了。
    
    2.
    
    USING T1 AS TB_SOURCE
    
    指定用来作为同步源的表或其他东东。USING是keyword,T1是原表名或一个子查询,比方一堆JOIN出来的东西用括号括起来。
    
    AS同上,TB_SOURCE是别名。
    
    3.
    
    ON TB_TARGET.ID2=TB_SOURCE.ID1
    
    关联条件,没什么好说的,注意这里開始就用到上面定义的别名了。
    
    4.
    
    WHEN NOT MATCHED BY TARGET THEN
    
    INSERT(ID2,VAL2)
    VALUES(ID1,VAL1)
    
    这里放到一起说。看到INSERT应该就能猜这段语句的意思是“假设原表有的记录新表没有,就插入”。
    
    NOT MATCHED表示不匹配, BY TARGET表示是新表找不到匹配原表条件(就是上面的ON后写的)的记录, BY TARGET 能够不写,默认就是BY TARGET,但假设要写两个WHEN MATCHED就必需要写,比方上面这个MERGE。
    
    第二三行和普通的插入语句差点儿相同,差别就在于没有目标表名和仅仅能用VALUES不能用SELECT,由于这里都是针对单行的操作。
    
    5.
    
    WHEN NOT MATCHED BY SOURCE THEN
    DELETE
    
    这个就简单了,假设是原表找不到新表的匹配记录,就把新表的删了。需要注意的就是假设要加上这句,上面的NOT MATCHED必须加BY TARGET。
    
    6.
    
    WHEN MATCHED AND TB_TARGET.VAL2<>TB_SOURCE.VAL1 THEN 
    UPDATE SET
    TB_TARGET.VAL2=TB_SOURCE.VAL1
    
    第一行后面的AND部分能够不要,相当于更新的另一个匹配条件,像上面样例中,ID为1的那条数据没有动,但由于能找到匹配记录还是会更新,加上条件就能够避免这样的无效操作了。
    
    7.
    
    OUTPUT $ACTION,ISNULL(DELETED.ID2,INSERTED.ID2) AS ID,DELETED.VAL2,INSERTED.VAL2
    
    这行能够都去掉,作用就是输出同步的数据,用过触发器的同学对INSERTED和DELETED两个表应该灰常熟悉,分别放的是更新后的值和更新前的值,看看最后一次MERGE输出的信息就能差点儿相同看出门道了,我就不多说了。假设要调试语句的话,能够加上这句,正常的同步就能够去掉了。
    
    8.
    
    ;
    
    这个必须有。。。。。
    
     
    
    总之,4,5,6,7都是能够去掉的,但4,5,6至少要有一个,这就是MERGE的所有经常使用语法了。另一个最后能够加 OPTION查询提示
    
     
     
    
    最后简单对照一下MERGE和原本相同效果的操作的IO对照
    
    MERGE INTO T2 AS TB_TARGET
    USING T1 AS TB_SOURCE
    ON TB_TARGET.ID2=TB_SOURCE.ID1
    WHEN NOT MATCHED BY TARGET THEN 
    INSERT(ID2,VAL2)
    VALUES(ID1,VAL1)
    WHEN NOT MATCHED BY SOURCE THEN
    DELETE
    WHEN MATCHED AND TB_TARGET.VAL2<>TB_SOURCE.VAL1 THEN 
    UPDATE SET
    TB_TARGET.VAL2=TB_SOURCE.VAL1
    OUTPUT $ACTION,ISNULL(DELETED.ID2,INSERTED.ID2) AS ID,DELETED.VAL2,INSERTED.VAL2
    ; 
    /*
    表 'T2'。扫描计数 2,逻辑读取 7 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
    表 'T1'。扫描计数 2,逻辑读取 4 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
    */ 
    PRINT '------------------------------------------------------------------------------------'
    INSERT INTO T2(ID2,VAL2)
    SELECT ID1,VAL1
    FROM T1 WHERE NOT EXISTS(
    SELECT 1 FROM T2 WHERE T2.ID2=T1.ID1
    )
    
    UPDATE T2
    SET T2.VAL2=T1.VAL1
    FROM T2
    INNER JOIN T1 ON T2.ID2=T1.ID1
    AND T2.VAL2<>T1.VAL1
    
    DELETE FROM T2 WHERE NOT EXISTS(
    SELECT 1 FROM T1 WHERE T1.ID1=T2.ID2
    ) 
    /*
    表 'T2'。扫描计数 1,逻辑读取 4 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
    表 'Worktable'。扫描计数 1,逻辑读取 5 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
    表 'T1'。扫描计数 1,逻辑读取 1 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
    表 'T2'。扫描计数 1,逻辑读取 2 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
    表 'T1'。扫描计数 1,逻辑读取 4 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
    表 'T2'。扫描计数 1,逻辑读取 1 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
    表 'T1'。扫描计数 1,逻辑读取 4 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
    */
    
     

  • 相关阅读:
    配置Apache虚拟主机
    Apache: You don't have permission to access / on this server
    wordpress之备份与恢复数据
    ruby之各种概念
    Oracle之比较NVARCHAR2字符串
    Centos安装ruby--jekyll
    Linux之IO Redirection
    SecureCRT导入已有会话
    jdk1.8新特性应用之Iterable
    jdk1.8新特性应用之Collection
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4195485.html
Copyright © 2011-2022 走看看