IF EXISTS 和 MERGE 语句

IF EXISTS and MERGE Statement

我有数据从多个其他 table 流入一个 table 让我们说:Table_A 然后我有一个合并存储过程,它从 table A 中获取数据并将其与 Table B.

合并

然而,似乎有些不对劲。如果我截断并加载数据,它工作正常,但如果我不截断和加载,只是按小时获取查询,我会收到错误消息说

消息 8672,级别 16,状态 1,过程 Merge_Table_A,第 4 行 [批处理起始行 0] MERGE 语句试图多次更新或删除同一行。当目标行匹配多个源行时会发生这种情况。 MERGE 语句不能 UPDATE/DELETE 目标的同一行 table 多次。优化 ON 子句以确保目标行最多匹配一个源行,或使用 GROUP BY 子句对源行进行分组。

我该如何克服这个问题?

我希望能够增量加载数据而不是截断加载,但同时有一个存储过程可以更新或插入或者不关心该行是否已经存在。

您的目标 table 中似乎有 重复行 ,这些行是从您之前的 运行 中加载的。

注意:合并中的匹配不考虑在 运行 合并本身时插入的行(甚至重复行)。

下面是我的重现示例和示例数据:

表 1:初始数据

表 2:目标 table

合并语句:

MERGE tb2 AS Target
USING tb1   AS Source
 ON Source.firstname = Target.firstname and 
    Source.lastname = Target.lastname 

-- For Inserts
WHEN NOT MATCHED BY Target THEN
INSERT (firstname, lastname, updated_date) 
VALUES (Source.firstname, Source.lastname, source.updated_date)

-- For Updates
WHEN MATCHED THEN UPDATE SET
   Target.updated_date      = Source.updated_date

-- For Deletes
WHEN NOT MATCHED BY Source THEN
DELETE;

执行 Merge 时,它​​会无误地插入所有数据。

tb1 中的新数据:

当我 运行 Merge 语句时,它给了我和你一样的错误。

作为解决方法,使用以下选项之一,

  1. 如果可能,在 ON 子句中添加附加条件,以唯一标识数据。

  2. 从源中删除重复项并将数据合并到 tb2 中,如下所示。

     --temp table
     drop table if exists #tb1;
    
     select *  into #tb1 from (
         select *, row_number() over(partition by firstname, lastname order by firstname, lastname, updated_date desc) as rn from tb1) a
     where rn = 1 
    
     MERGE tb2 AS Target
     USING #tb1 AS Source
      ON Source.firstname = Target.firstname and 
         Source.lastname = Target.lastname 
    
     -- For Inserts
     WHEN NOT MATCHED BY Target THEN
     INSERT (firstname, lastname, updated_date) 
       VALUES (Source.firstname, Source.lastname, source.updated_date)
    
     -- For Updates
     WHEN MATCHED THEN UPDATE SET
        Target.updated_date     = Source.updated_date
    
     -- For Deletes
     WHEN NOT MATCHED BY Source THEN
       DELETE;
    

数据合并到tb2成功