合并语句错误调试

时间:2017-02-04 19:46:59

标签: sql-server tsql stored-procedures merge sql-server-2012

我有一种情况,我有一个包含合并声明的存储过程。该过程从表A中获取数据并使用merge语句更新表B中的某些记录。该过程工作正常但偶尔会出现表A中存在重复记录的情况。存储过程位于包含错误通知集的包中up并且程序包在作业中运行,它给出了以下错误。有什么办法可以调试吗?像存储过程中的某些地方一样,如果它出错,那么将源数据插入表中?任何意见都表示赞赏。

由于

错误:

  

失败并出现以下错误:“MERGE语句尝试了   多次更新或删除同一行。这发生在a   目标行匹配多个源行。 MERGE声明不能   多次更新/删除目标表的同一行。提炼   ON子句,以确保目标行最多匹配一个源行,   或使用GROUP BY子句对源行进行分组。“。可能   失败原因:查询问题,“ResultSet”属性未设置   正确,参数设置不正确,或连接未建立   正确。

1 个答案:

答案 0 :(得分:2)

您可以在合并程序的开头添加类似的内容:

if exists (
  select 1 
    from a 
    group by a.OnColumn 
    having count(*)>1
    )
  begin;
    insert into merge_err (OnColumn, OtherCol, rn, cnt)
      select 
          a.OnColumn
        , a.OtherCol
        , rn = row_number() over (
            partition by OnColumn
            order by OtherCol 
            )
        , cnt = count(*) over (
            partition by OnColumn
            )
        from a
    raiserror( 'Duplicates in source table a', 0, 1)
    return -1;
  end;

测试设置:http://rextester.com/EFZ77700

create table a (OnColumn int, OtherCol varchar(16))
insert into a values 
    (1,'a')
  , (1,'b')
  , (2,'c')

create table b (OnColumn int primary key, OtherCol varchar(16))
insert into b values 
    (1,'a')
  , (2,'c')


create table merge_err (
    id int not null identity(1,1) primary key clustered
  , OnColumn int
  , OtherCol varchar(16)
  , rn int
  , cnt int
  , ErrorDate datetime2(7) not null default sysutcdatetime()
  );

go

虚拟程序:

create procedure dbo.Merge_A_into_B as 
begin
set nocount, xact_abort on;
if exists (
  select 1 
    from a 
    group by a.OnColumn 
    having count(*)>1
    )
  begin;
    insert into merge_err (OnColumn, OtherCol, rn, cnt)
      select 
          a.OnColumn
        , a.OtherCol
        , rn = row_number() over (
            partition by OnColumn
            order by OtherCol 
            )
        , cnt = count(*) over (
            partition by OnColumn
            )
        from a
    raiserror( 'Duplicates in source table a', 0, 1)
    return -1;
  end;

/*
merge into b 
  using a 
  on b.OnColumn = a.OnColumn
  ...
--*/
end;
go

执行test proc并检查错误表:

exec dbo.Merge_A_into_B

select * 
from merge_err
where cnt > 1

结果:

+----+----------+----------+----+-----+---------------------+
| id | OnColumn | OtherCol | rn | cnt |      ErrorDate      |
+----+----------+----------+----+-----+---------------------+
|  1 |        1 | a        |  1 |   2 | 05.02.2017 17:22:39 |
|  2 |        1 | b        |  2 |   2 | 05.02.2017 17:22:39 |
+----+----------+----------+----+-----+---------------------+