1

好的,所以我从其他帖子/网站了解到,以下查询样式将自动执行:

INSERT INTO Foo(field1, field2) 
SELECT @field1, @field2 
WHERE NOT EXISTS (SELECT * FROM Foo 
                  WHERE Field1 = @field1 
                     OR Field2 = @field2)

这将用于满足 field1 和 field2 都是唯一的设计要求。到目前为止,一切都很好,花花公子。

但是,在这样的记录已经存在的情况下(查询插入 0 行),如果我想知道 WHICH 字段已经有一条具有相同值的记录该怎么办。(即,以下哪些陈述是正确的?

  • 已有一条记录,其中 Field1 = @field1
  • 已有一条记录,其中 Field2 = @field2
  • 以上两者

您需要知道哪个字段有问题,以便显示一条错误消息,告诉用户他们需要将哪个字段更改为唯一值。我总是可以检查第二个查询,但这不是原子的。尝试插入和第二次查询之间的数据可能已更改,以确定哪个字段有问题,并且错误消息可能无法反映数据库的实际状态。

关于如何处理这种情况的任何想法?

4

2 回答 2

0

假设:

  1. 您希望大多数 INSERT 都能成功。
  2. 您有一个独特的约束,因此错误的INSERT 将失败。
  3. 您不关心匹配 NULL。

    set transaction isolation level serializable;
    begin transaction;
    begin try
      insert into Foo ( Field1, Field2 ) values ( @Field1, @Field2 );
    end try
    begin catch
    -- Really ought to confirm that the error was the expected one here.
    select
        @Field1Match = case when Field1 = @Field1 then Cast( 1 as Bit ) else Cast( 0 as Bit ) end,
        @Field2Match = case when Field2 = @Field2 then Cast( 1 as Bit ) else Cast( 0 as Bit ) end
        from Foo
        where Field1 = @Field1 or Field2 = @Field2;
    end catch;
    commit transaction;
    
于 2013-09-27T01:12:37.327 回答
0

根据我的研究(此处此处),除非您非常有信心超过 95% 的插入会成功,否则我会使用与 HABO 相反的方法。借用您不关心匹配 NULL 的相同假设:

DECLARE @Col1Match VARCHAR(20), @Col2Match VARCHAR(20), @msg NVARCHAR(4000);

SET ANSI_WARNINGS OFF;

BEGIN TRANSACTION;

SELECT @Col1Match = MAX(CASE Field1 WHEN @Field1 THEN 'Field1 exists:' END),
       @Col2Match = MAX(CASE Field2 WHEN @Field2 THEN 'Field2 exists:' END)
FROM dbo.Foo WITH (HOLDLOCK)
WHERE Field1 = @Field1 OR Field2 = @Field2;

IF @Col1Match IS NULL AND @Col2Match IS NULL
BEGIN
  INSERT dbo.Foo(Field1, Field2) SELECT @Field1, @Field2;
END
ELSE
BEGIN
  SET @msg = LTRIM(COALESCE(' ' + @Col1Match + ' (' + @Field1 + ')', '')
           + COALESCE(' ' + @Col2Match + ' (' + @Field2 + ')', ''));
END

COMMIT TRANSACTION;

IF @msg IS NOT NULL
BEGIN
  RAISERROR(@msg, 11, 1);
END
于 2013-09-27T12:51:59.983 回答