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

Tsql 使用T-SQL合并更新现有记录并插入不存在但避免重复的记录,tsql,merge,sql-update,sql-insert,sql-merge,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:2

我有两张结构相同的表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 Z41,t1中有更多的值,例如tid的包括1、2、3、4、5和11。但t2中只存在1、2、3和11

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

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和tid的副本,其中updtby列读取“MERGEDINSERT”。但我想避免重复

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


按照您描述的方式,合并条件应仅基于pid和tid。试试这个

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');
如果由于获取多个记录/匹配而导致合并引发错误,则可以使用子查询中的聚合来限制源表,例如:

;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');

是否可以从ON条款中删除日期和金额?您所显示的数据的期望输出是什么?在on子句中只保留pid和tid会产生以下结果:MERGE语句多次尝试更新或删除同一行。当目标行与多个源行匹配时,会发生这种情况。MERGE语句不能多次更新/删除目标表的同一行。优化ON子句以确保目标行最多匹配一个源行,或使用GROUP BY子句对源行进行分组。@gh0st这意味着您将获得pid/tid组合的多个匹配项。期望的输出是什么?你能在日期上使用MAX吗?基本上,我想用t1中的匹配记录更新t2中的任何记录,如果pid+tid组合记录不存在,我想插入它。但是你的错误是,一些pid+tid记录存在不止一次,那么你如何知道在更新中使用哪些值呢?以记录pid=Z41为例,tid=3英寸t2。我想更新该记录以匹配t1中的内容,以便将startdate和enddate设置为t1中相应的值。然后,对于记录pid=Z41、tid=4和pid=Z41、tid=5,我想将这些记录插入t2。列“dbo.t1.pid”在选择列表中无效,因为它不包含在聚合函数或GROUP BY子句中。将内部联接中的select更改为从t1 GROUP BY pid中选择pid、tid、maxpaymentdt作为maxdt,但是仍然插入重复项,因为tgt.startdate=src.startdate上没有匹配项。