在 SQL 服务器中尝试捕获?
Try-Catch in SQL Server?
所以我最近开始在大学 SQL 服务器中处理事务和错误处理,我 运行 遇到了这个我的老师无法解释的问题。当我尝试执行此块时:
Begin Transaction TRA
Begin Try
Alter Table history
Add Primary Key (employee_id,date_beg)
End Try
Begin catch
If @@trancount>0
Select ERROR_NUMBER() Error, ERROR_MESSAGE() Mensaje
End Catch
Commit
我收到以下错误消息:
Msg 8111, Level 16, State 1, Line 2
Cannot define PRIMARY KEY constraint on nullable column in table 'history'.
Msg 1750, Level 16, State 0, Line 2
Could not create constraint. See previous errors.
看来代码没有像预期的那样捕获错误。
如果你能帮助我,我将不胜感激!
根据 BOL,Try Catch 在以下情况下不起作用:
an error that occurs during statement-level recompilation will not
prevent the batch from compiling, but it will terminate the batch as
soon as recompilation for the statement fails. For example, if a batch
has two statements and the second statement references a table that
does not exist, deferred name resolution causes the batch to compile
successfully and start execution without binding the missing table to
the query plan until that statement is recompiled. The batch stops
running when it gets to the statement that references the missing
table and returns an error. This type of error will not be handled by
a TRY…CATCH construct at the same level of execution at which the
error occurred.
Methinx 这就是问题所在。
根据 documentation on TRY...CATCH,我认为您的 CATCH
块应该已经捕获了错误。
这些是错误不会在 TRY...CATCH
块中被捕获的记录原因,其中 none 似乎适用于您的情况:
TRY…CATCH
constructs do not trap the following conditions:
- Warnings or informational messages that have a severity of
10
or lower.
- Errors that have a severity of
20
or higher that stop the SQL Server Database Engine task processing for the session. If an error occurs that has severity of 20
or higher and the database connection is not disrupted, TRY…CATCH
will handle the error.
- Attentions, such as client-interrupt requests or broken client connections.
- When the session is ended by a system administrator by using the
KILL
statement.
The following types of errors are not handled by a CATCH
block when they occur at the same level of execution as the TRY…CATCH
construct:
- Compile errors, such as syntax errors, that prevent a batch from running.
- Errors that occur during statement-level recompilation, such as object name resolution errors that occur after compilation because of deferred name resolution.
特别考虑最后两个原因,这不是编译错误,也不是延迟名称解析错误,因为您的 table 名称解析得很好。这确实是一个运行时错误,应该被捕获。
然而,尽管它在这里不适用,但您会发现以下信息为您的案例提供了可行的解决方案:
If an error occurs during compilation or statement-level recompilation at a lower execution level (for example, when executing sp_executesql
or a user-defined stored procedure) inside the TRY
block, the error occurs at a lower level than the TRY…CATCH
construct and will be handled by the associated CATCH
block.
应用以上信息,您会发现可以通过将脚本更改为以下两个选项之一来捕获错误:
选项 1:sp_executesql
Begin Transaction TRA
Begin Try
exec sp_executesql 'Alter Table history Add Primary Key (employee_id,date_beg)';
End Try
Begin catch
If @@trancount>0
Select ERROR_NUMBER() Error, ERROR_MESSAGE() Mensaje
End Catch
Commit
选项 2:将 alter 语句包装在单独的存储过程中
create procedure WrapAlterStatementInSP as
Alter Table history Add Primary Key (employee_id,date_beg);
go
Begin Transaction TRA
Begin Try
exec WrapAlterStatementInSP;
End Try
Begin catch
If @@trancount>0
Select ERROR_NUMBER() Error, ERROR_MESSAGE() Mensaje
End Catch
Commit
希望这对您有所帮助。但我确实觉得当前行为中存在错误,或者文档中缺少信息。
所以我最近开始在大学 SQL 服务器中处理事务和错误处理,我 运行 遇到了这个我的老师无法解释的问题。当我尝试执行此块时:
Begin Transaction TRA
Begin Try
Alter Table history
Add Primary Key (employee_id,date_beg)
End Try
Begin catch
If @@trancount>0
Select ERROR_NUMBER() Error, ERROR_MESSAGE() Mensaje
End Catch
Commit
我收到以下错误消息:
Msg 8111, Level 16, State 1, Line 2
Cannot define PRIMARY KEY constraint on nullable column in table 'history'.Msg 1750, Level 16, State 0, Line 2
Could not create constraint. See previous errors.
看来代码没有像预期的那样捕获错误。
如果你能帮助我,我将不胜感激!
根据 BOL,Try Catch 在以下情况下不起作用:
an error that occurs during statement-level recompilation will not prevent the batch from compiling, but it will terminate the batch as soon as recompilation for the statement fails. For example, if a batch has two statements and the second statement references a table that does not exist, deferred name resolution causes the batch to compile successfully and start execution without binding the missing table to the query plan until that statement is recompiled. The batch stops running when it gets to the statement that references the missing table and returns an error. This type of error will not be handled by a TRY…CATCH construct at the same level of execution at which the error occurred.
Methinx 这就是问题所在。
根据 documentation on TRY...CATCH,我认为您的 CATCH
块应该已经捕获了错误。
这些是错误不会在 TRY...CATCH
块中被捕获的记录原因,其中 none 似乎适用于您的情况:
TRY…CATCH
constructs do not trap the following conditions:
- Warnings or informational messages that have a severity of
10
or lower.- Errors that have a severity of
20
or higher that stop the SQL Server Database Engine task processing for the session. If an error occurs that has severity of20
or higher and the database connection is not disrupted,TRY…CATCH
will handle the error.- Attentions, such as client-interrupt requests or broken client connections.
- When the session is ended by a system administrator by using the
KILL
statement.The following types of errors are not handled by a
CATCH
block when they occur at the same level of execution as theTRY…CATCH
construct:
- Compile errors, such as syntax errors, that prevent a batch from running.
- Errors that occur during statement-level recompilation, such as object name resolution errors that occur after compilation because of deferred name resolution.
特别考虑最后两个原因,这不是编译错误,也不是延迟名称解析错误,因为您的 table 名称解析得很好。这确实是一个运行时错误,应该被捕获。
然而,尽管它在这里不适用,但您会发现以下信息为您的案例提供了可行的解决方案:
If an error occurs during compilation or statement-level recompilation at a lower execution level (for example, when executing
sp_executesql
or a user-defined stored procedure) inside theTRY
block, the error occurs at a lower level than theTRY…CATCH
construct and will be handled by the associatedCATCH
block.
应用以上信息,您会发现可以通过将脚本更改为以下两个选项之一来捕获错误:
选项 1:sp_executesql
Begin Transaction TRA
Begin Try
exec sp_executesql 'Alter Table history Add Primary Key (employee_id,date_beg)';
End Try
Begin catch
If @@trancount>0
Select ERROR_NUMBER() Error, ERROR_MESSAGE() Mensaje
End Catch
Commit
选项 2:将 alter 语句包装在单独的存储过程中
create procedure WrapAlterStatementInSP as
Alter Table history Add Primary Key (employee_id,date_beg);
go
Begin Transaction TRA
Begin Try
exec WrapAlterStatementInSP;
End Try
Begin catch
If @@trancount>0
Select ERROR_NUMBER() Error, ERROR_MESSAGE() Mensaje
End Catch
Commit
希望这对您有所帮助。但我确实觉得当前行为中存在错误,或者文档中缺少信息。