问题应该很简单,但我无法弄清楚答案,也不能解释为什么我的存储过程无效。
CREATE PROCEDURE spTest_Delete
@ID int
AS
begin tran
declare @err int
declare @errMesage nvarchar(max)
set @errMesage = ''
set @err = 0
delete from Test
where ID = @ID
set @err = @@ERROR
set @errMesage = ERROR_MESSAGE()
if @err = 0
commit tran
else
begin
RAISERROR(N'Could not delete !Error nr: %d. Message: %s', 1, 16, @err, @errMesage)
rollback tran
end
这个程序运行正常,但是如果delete
语句有FK约束,它会遇到错误(这很好),我想抓住错误。
Msg 547,Level 16,State 0,Procedure spTest_Delete,Line 12
DELETE语句与REFERENCE约束冲突 “FK_TEstFK_Test”。冲突发生在数据库“Test”,表中 “dbo.Test”,列'ID'。该语句已终止。无法删除!
错误号:547。消息:( null)消息50000,级别1,状态16
我的消息变量总是为null,即使delete
语句引发错误。
答案 0 :(得分:5)
您可能希望在程序中使用TRY..CATCH阻止
实现类似于的Transact-SQL的错误处理 Microsoft Visual C#和Microsoft Visual C ++中的异常处理 语言。一组Transact-SQL语句可以包含在TRY中 块。如果TRY块中发生错误,则传递控制权 另一组语句包含在CATCH块中。
所以你的程序可以改写为:
CREATE PROCEDURE spTest_Delete @ID INT
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRANSACTION
DELETE
FROM Test
WHERE ID = @ID;
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION
SELECT ERROR_NUMBER(), ERROR_MESSAGE();
END CATCH
END
此外,请注意您作为单个删除语句运行。这意味着它不需要包含在事务中。 This问题解释了原因。
您的代码变为:
CREATE PROCEDURE spTest_Delete @ID INT
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
DELETE
FROM Test
WHERE ID = @ID;
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER(), ERROR_MESSAGE();
END CATCH
END
为什么你的@errMessage
总是为空?因为ERROR_MESSAGE()
仅在CATCH块中有效。这是用documentation写的:
返回导致CATCH块的错误的消息文本 TRY ... CATCH构造要运行。
Using TRY..CATCH in Transact-SQL告诉我们:
从任何地方使用这些函数检索错误信息 在TRY ... CATCH构造的CATCH块的范围内。 错误 如果在CATCH范围之外调用,函数将返回NULL 块强>
答案 1 :(得分:3)
尝试使用TRY CATCH并捕获您的错误:
BEGIN TRY
delete from Test
where ID = @ID
END TRY
BEGIN CATCH
SET @ErrorMessage = ERROR_MESSAGE()
SET @ErrorSeverity = ERROR_SEVERITY()
SET @ErrorState = ERROR_STATE()
RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState)
BREAK
END CATCH