2017-07-14 59 views
0

假设我有一个SELECTINSERTUPDATE语句的存储过程。如果其中的某个查询失败,存储过程是否会失败?

事务块内没有内容。也没有Try/Catch块。 我也有XACT_ABORT设置为OFF。

如果INSERT失败,UPDATE仍然有可能发生?

INSERT失败的原因是因为我将空值传递给不允许的列。我只能访问被称为存储过程的程序抛出的异常,并且它没有任何严重性级别,据我所知。

+0

这取决于您的过程中的错误处理代码:如果您有'TRY ... CATCH'块。 – Dai

+0

没有尝试捕捉块 – xMetalDetectorx

+1

谁控制存储过程?你的编辑有点不清楚,这听起来像你改变了你的问题。您的原始问题是:更新是否仍然可以发生?答:是的。你已经添加了一些额外的陈述,这些陈述并没有改变你的答案,也没有改变你的要求。现在你的新问题意味着:我不控制proc;我如何从中获得体面的错误信息? – Alan

回答

3

可能。这取决于失败的严重程度。

用户代码错误通常是16.

超过20的任何情况都是自动失败。

重复密钥阻塞插入将是14,即非致命的。

将NULL插入到不支持它的列中 - 这被视为用户代码错误(16) - 因此不会导致批处理暂停。 UPDATE将继续。

另一个主要因素是如果批处理的XACT_ABORT配置为ON。这将导致任何失败中止整批。

下面是一些进一步阅读:

list-of-errors-and-severity-level-in-sql-server-with-catalog-view-sysmessages

exceptionerror-handling-in-sql-server

而对于XACT_ABORT

https://www.red-gate.com/simple-talk/sql/t-sql-programming/defensive-error-handling/

https://docs.microsoft.com/en-us/sql/t-sql/statements/set-xact-abort-transact-sql

为了理解存储过程中任何步骤的结果,具有适当权限的人员(例如,管理员)需要编辑存储的proc并捕获错误消息。这将给出关于存储过程的进度的反馈。一个非结构化错误(即不在try/catch中)代码为0表示成功,否则将包含错误代码(我认为对于NULL插入来说,它将为515)。这是非常理想的,因为它仍然不会导致批处理停止,但会警告您存在问题。

最简单的例子:

DECLARE @errnum AS int; 
-- Run the insert code 
SET @errnum = @@ERROR; 
PRINT 'Error code: ' + CAST(@errornum AS VARCHAR); 

错误处理可以是一个复杂的问题;它需要对数据库结构和预期传入数据有重要的了解。

选项可以包括使用中间步骤(如HLGEM所述),修改INSERT以包含ISNULL/COALESCE语句以清除空值,检查客户端上的数据以消除麻烦的问题等。如果知道预计要插入的行数,则存储的proc可以返回SET @[email protected]@ROWCOUNT,方法与SET @errnum = @@ERROR相同。

如果您对存储过程没有权限,并且没有能力说服管理员修改它,那么您可以做的事情并不多。

如果您有权直接对数据库运行自己的查询(而不是通过存储过程或视图),那么您可以通过对原始数据运行自己的查询来推断结果,执行存储过程更新,然后重新运行您的查询并查找更改。如果您有权限,则还可以尝试查询事务日志(fn_dblog)或错误日志(sp_readerrorlog)。

+0

感谢您的所有信息! XACT_ABORT对我来说是关闭的。我只能访问我的程序抛出的异常,而且我没有看到严重程度。 “插入”失败的原因是因为我将空值传递给不接受空值的列。 – xMetalDetectorx

+1

由于数据完整性原因,您通常希望所有步骤都在发生故障时进行回滚。所以我个人会修复存储过程来做到这一点,并适当地冒出错误。如果您创建一个表变量来存储步骤或输入数据的信息,或者在每个步骤之后填充错误和填充信息,那么当您回滚该信息仍然可用时,可以将其插入真实表格中,以便您可以准确查找发生了。 – HLGEM