为什么使用Throw的自定义异常不会执行下一个语句,而表约束异常会执行它

时间:2014-12-04 09:47:37

标签: sql-server-2012

我有一个包含Id smallint和Code varchar(5)字段的表,Code上有一个唯一键约束。 已经有一排“ABC'在表

中的代码字段中

我写了以下存储过程来向其中插入值

            ALTER Procedure [dbo].[Insert]
                @Id smallint output,
                @Code varchar(5)
            AS
            SET NOCOUNT OFF;
            IF not EXISTS (select Code from SomeTable where Code like '%'+@Code and Code <> @Code)
            BEGIN
                Insert into dbo.SomeTable (Code) values (@Code)
            END
            ELSE
            BEGIN
               Throw 50000,'Violation of UNIQUE KEY constraint. Cannot insert Code which is already a suffix of existing Code in table ''dbo.SomeTable''.',1
            END
            Select Id,Code from dbo.SomeTable  where SomeTableCode = 'ABC'

你可以看到我编写了自定义抛出异常,当代码作为任何现有代码的后缀存在时,应该抛出此异常。

当我使用以下语句测试插入重复代码时

    DECLARE @return_value int,
            @Id smallint

    EXEC    @return_value = [dbo].[Insert]
            @Id = @Id OUTPUT,
            @Code = N'ABC'

我得到以下异常:

    Msg 2627, Level 14, State 1, Procedure Insert, Line 19
    Violation of UNIQUE KEY constraint 'IX_SomeTable_1'. Cannot insert duplicate key in object 'dbo.SomeTable'. The duplicate key value is (ABC).
    The statement has been terminated.
    (1 row(s) affected)

我可以看到结果选项卡中的行(选择执行的语句)

但是当我尝试使用以下语句将Code作为后缀插入表中的其他代码时:

    DECLARE @return_value int,
            @Id smallint

    EXEC    @return_value = [dbo].[Insert]
            @Id = @Id OUTPUT,
            @Code = N'BC'

我收到以下错误,但Select语句未执行,我在“结果”标签中看不到行,为什么?

    Msg 50000, Level 16, State 1, Procedure Insert, Line 24
    Violation of UNIQUE KEY constraint. Cannot insert Code which is already a suffix of existing Code in table 'dbo.SomeTable'.

1 个答案:

答案 0 :(得分:0)

根据THROW on MSDN

  

如果TRY ... CATCH构造不可用,则会话结束

您没有使用TRY / CATCH,因此THROW会停止执行存储过程。

一般来说,这个支付方式是不可靠的

  • 两个并发会话都可以找到NOT EXISTS为真,但只有一个插入可以成功。使用MERGE
  • THROW显示&#34;已经存在或存在为后缀&#34;,它实际上不是违规
  • no TRY / CATCH

编辑,使用类似

的内容
BEGIN TRY
    MERGE into dbo.SomeTable
    etc

END TRY
BEGIN CATCH
    DECLARE @errmsg nvarchar(2000);
    IF ERROR_NUMBER() = 2627
        SET @errmsg = 'Already exists etc'
    ELSE
        SET @errmsg = ERROR_MESSAGE();
    THROW 50000, @errmsg, 1;
END CATCH
SELECT Id,Code from dbo.SomeTable  where SomeTableCode = 'ABC';

完全阅读Error Handling in SQL 2005 and Later