使用T-SQL Merge更新现有记录并插入不存在的记录但避免重复

时间:2015-10-27 20:31:51

标签: tsql merge sql-update sql-insert sql-merge

我有两张结构相同的表t1和t2 表t1比t2有大约100多条记录。

这里是t1的一小部分样本。

| pid   | tid    | amt         | paymentdt  | paymentmnth   | startdate                 | enddate                   | updtby
| 670   | 1      | 690.00      | 2015-07-07 | 2015-07-07    | 2015-10-26 14:36:27.000   | 2015-10-26 15:42:42.000   | NULL
| 670   | 11     | 855.00      | 2015-07-07 | 2015-07-07    | 2015-10-26 14:36:27.000   | NULL                      | NULL
| 670   | 13     | 129.00      | 2015-07-29 | 2015-07-29    | 2015-10-26 14:36:27.000   | NULL                      | NULL
| 670   | 2      | 855.00      | 2015-09-01 | 2015-09-01    | 2015-10-26 15:42:42.000   | NULL                      | NULL
| Z41   | 1      | 62.35       | 2015-05-08 | 2015-05-08    | 2015-10-26 10:15:24.000   | 2015-10-26 13:08:05.000   | NULL
| Z41   | 11     | 800.00      | 2015-05-08 | 2015-05-08    | 2015-10-26 10:15:24.000   | NULL                      | NULL
| Z41   | 2      | 298.00      | 2015-06-01 | 2015-06-01    | 2015-10-26 13:08:05.000   | 2015-10-26 14:36:27.000   | NULL
| Z41   | 3      | 298.00      | 2015-07-01 | 2015-07-01    | 2015-10-26 14:36:27.000   | 2015-10-26 15:15:45.000   | NULL
| Z41   | 4      | 298.00      | 2015-08-01 | 2015-08-01    | 2015-10-26 15:15:45.000   | 2015-10-26 15:42:42.000   | NULL
| Z41   | 5      | 238.00      | 2015-09-01 | 2015-09-01    | 2015-10-26 15:42:42.000   | NULL                      | NULL

还有一小部分t2。

| pid   | tid    | amt         | paymentdt   | paymentmnt   | startdate                 | enddate                   | updtby
| 670   | 1      | 690.00      | 2015-07-07  | 2015-07-07   | 2015-10-02 16:10:50.000   | 2015-10-02 16:35:50.000   | NULL  
| 670   | 11     | 855.00      | 2015-07-07  | 2015-07-07   | 2015-10-02 16:10:50.000   | NULL                      | NULL  
| 670   | 13     | 129.00      | 2015-07-29  | 2015-07-29   | 2015-10-02 16:10:50.000   | NULL                      | NULL  
| 670   | 2      | 855.00      | 2015-09-01  | 2015-09-01   | 2015-10-02 16:35:50.000   | NULL                      | NULL  
| Z41   | 1      | 298.00      | 2015-07-01  | 2015-07-01   | 2015-10-02 16:10:50.000   | 2015-10-02 16:23:26.000   | NULL  
| Z41   | 11     | 800.00      | 2015-05-08  | 2015-05-08   | 2015-10-02 16:10:50.000   | NULL                      | NULL  
| Z41   | 2      | 298.00      | 2015-08-01  | 2015-08-01   | 2015-10-02 16:23:26.000   | 2015-10-02 16:35:50.000   | NULL  
| Z41   | 3      | 238.00      | 2015-09-01  | 2015-09-01   | 2015-10-02 16:35:50.000   | NULL                      | NULL  
| 173   | 1      | 785.00      | 2015-07-01  | 2015-07-01   | 2015-10-02 16:16:30.000   | 2015-10-02 16:27:36.000   | NULL  
| 173   | 11     | 465.00      | 2015-05-01  | 2015-05-01   | 2015-10-02 16:16:30.000   | NULL                      | NULL  

现在比较t1和t2显示pid中{p} Z41的值更多,例如tid包括1,2,3,4,5和11.但是在t2中只存在1 ,2,3和11.

然而,t1和t2之间的起始日期完全不同,所以这会引发一些麻烦。下面是我尝试过的合并,但它基本上只是在t2中插入与t1不同的startdate的每一行。

MERGE INTO t2 AS tgt
USING t1 AS src
    ON tgt.pid = src.pid AND
       tgt.tid = src.tid AND
       tgt.paymentdt = src.paymentdt AND
       tgt.paymentmnt = src.paymentmnt AND
       tgt.startdate = src.startdate
WHEN MATCHED THEN
    UPDATE SET
        tgt.amt = src.amt,
        tgt.paymentdt = src.paymentdt,
        tgt.updatedby = 'MERGEDUPDATE'
WHEN NOT MATCHED THEN
    INSERT (pid, tid, amt, paymentdt, paymentmnt, startdate, enddate, updtby)
    VALUES (src.pid, src.tid, src.amt, src.paymentdt, src.paymentmnt, src.startdate, src.enddate, 'MERGEDINSERT');

通过此合并,我留下了pid and tid的重复项,其中updtby列读取了' MERGEDINSERT'。但我想避免重复。

  

如何正确地进行此合并以产生重复项,但是   插入存在于t1但不存在于t2中的行,同时还更新   保持startdate值amt, paymentdt, and paymentmnth值?

2 个答案:

答案 0 :(得分:0)

您描述它的方式,您的合并标准应仅基于pidtid。试试这个

MERGE INTO t2 AS tgt
USING t1 AS src
    ON tgt.pid = src.pid AND
       tgt.tid = src.tid 

WHEN MATCHED THEN
    UPDATE SET
        tgt.amt = src.amt,
        tgt.paymentdt = src.paymentdt,
        tgt.paymentmnth  = src.paymentmnth, 
        tgt.updatedby = 'MERGEDUPDATE'
WHEN NOT MATCHED THEN
    INSERT (pid, tid, amt, paymentdt, paymentmnt, startdate, enddate, updtby)
    VALUES (src.pid, src.tid, src.amt, src.paymentdt, src.paymentmnt, src.startdate, src.enddate, 'MERGEDINSERT');

答案 1 :(得分:0)

如果您MERGE因为获取多个记录/匹配而引发错误,则可以使用子查询中的聚合来限制Source表,例如:

;WITH t1cte AS (
    select pid, tid, amt, paymentdt, paymentmnt, startdate, enddate
    from t1 a
      inner join (select pid,tid,MAX(paymentdt) as maxdt from t1 group by pid,tid) b
        on a.pid = b.pid and a.tid = b.tid and a.paymentdt = b.maxdt
        )

MERGE INTO t2 AS tgt
USING t1cte AS src
    ON tgt.pid = src.pid AND
       tgt.tid = src.tid AND
       tgt.paymentdt = src.paymentdt AND
       tgt.paymentmnt = src.paymentmnt AND
       tgt.startdate = src.startdate
WHEN MATCHED THEN
    UPDATE SET
        tgt.amt = src.amt,
        tgt.paymentdt = src.paymentdt,
        tgt.updatedby = 'MERGEDUPDATE'
WHEN NOT MATCHED THEN
    INSERT (pid, tid, amt, paymentdt, paymentmnt, startdate, enddate, updtby)
    VALUES (src.pid, src.tid, src.amt, src.paymentdt, src.paymentmnt, src.startdate, src.enddate, 'MERGEDINSERT');