Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/83.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在SQL Server中重新显示相同的异常_Sql_Sql Server_Database_Tsql_Exception - Fatal编程技术网

如何在SQL Server中重新显示相同的异常

如何在SQL Server中重新显示相同的异常,sql,sql-server,database,tsql,exception,Sql,Sql Server,Database,Tsql,Exception,我想在SQL Server中重新引发刚才在我的try块中发生的相同异常。我可以抛出相同的消息,但我想抛出相同的错误 BEGIN TRANSACTION BEGIN TRY INSERT INTO Tags.tblDomain (DomainName, SubDomainId, DomainCode, Description) VALUES(@DomainName, @SubDomainId, @DomainCode, @Description)

我想在SQL Server中重新引发刚才在我的try块中发生的相同异常。我可以抛出相同的消息,但我想抛出相同的错误

BEGIN TRANSACTION
    BEGIN TRY
        INSERT INTO Tags.tblDomain (DomainName, SubDomainId, DomainCode, Description)
            VALUES(@DomainName, @SubDomainId, @DomainCode, @Description)
        COMMIT TRANSACTION
    END TRY
    
    BEGIN CATCH
        declare @severity int; 
        declare @state int;

        select @severity=error_severity(), @state=error_state();

        RAISERROR(@@Error,@ErrorSeverity,@state);
        ROLLBACK TRANSACTION
    END CATCH
RAISERROR(@@Error,@ErrorSeverity,@state)

这一行将显示错误,但我希望类似的功能。 这将引发错误号为50000的错误,但我希望抛出我正在传递的错误号
@@error

我想在前端捕获此错误号

i、 e

我想要这个功能。这是使用
raiseerror
无法实现的。我不想在后端给出自定义错误消息

RAISEERROR
当我传递要在catch中抛出的ErrorNo时,应该返回下面提到的错误

第14行 违反唯一密钥约束“UK_DomainCode”。无法插入 对象中的重复密钥 “Tags.tblDomain”。 声明已终止

编辑:


考虑到存储过程包含多个需要执行的查询,如果我希望在前端处理异常,那么不使用try-catch块有什么缺点?

我认为您的选择是:

  • 不要抓住错误(让它冒出来)
  • 自订

在某些时候,SQL可能会引入一个reraise命令,或者只捕获某些错误的能力。但现在,使用一种变通方法。抱歉。

好的,这是一个解决方法…:-)

如果您注意到catch块,它不会引发错误,而是返回实际的错误号(并且还会回滚事务)。现在在.NET代码中,而不是捕获 例外情况,如果使用ExecuteScalar(),则会获得所需的实际错误号并显示相应的数字

int errorNumber=(int)command.ExecuteScalar();
if(errorNumber=<SomeNumber>)
{
    MessageBox.Show("Some message");
}
int errorNumber=(int)command.ExecuteScalar();
if(errorNumber=)
{
MessageBox.Show(“一些消息”);
}
希望这有帮助


EDIT:-请注意,如果您想获得受影响的记录数并尝试使用ExecuteOnQuery,上述解决方案可能不适用于您。否则,我想它会满足你的需要。让我知道。

你不能:只有引擎可以抛出小于50000的错误。你所能做的就是抛出一个看起来像它的异常


这里的提问者使用客户端事务来做他想做的事情,我认为这有点愚蠢…

从设计的角度来看,抛出带有原始错误号和自定义消息的异常有什么意义?在某种程度上,它打破了应用程序和数据库之间的接口契约。
如果希望捕获原始错误并在更高的代码中处理它们,请不要在数据库中处理它们。然后,当您捕获到异常时,您可以将呈现给用户的消息更改为您想要的任何内容。但我不会这么做,因为这会使您的数据库代码“嗯,不对”。正如其他人所说,您应该定义一组自己的错误代码(50000以上)并抛出它们。然后,您可以将完整性问题(“不允许重复值”)与潜在的业务问题分开处理——“邮政编码无效”、“未找到与标准匹配的行”等等。

这里是一个功能完整的干净代码示例,用于在发生错误时回滚一系列语句并报告错误消息

begin try
    begin transaction;

    ...

    commit transaction;
end try
begin catch
    if @@trancount > 0 rollback transaction;
    throw;
end catch
SQL 2012之前

begin try
    begin transaction;
    
    ...
    
    commit transaction;
end try
begin catch
    declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
    select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
    if @@trancount > 0 rollback transaction;
    raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch

SQL 2012引入了throw语句:

如果指定的THROW语句没有参数,则它必须出现 在一个挡块里面。这将导致引发捕获的异常


在发生错误后,停止存储过程中的执行并将错误冒泡回调用程序的方法是,在可能引发错误的每个语句后面执行以下代码:

If @@ERROR > 0
Return
我自己很惊讶地发现,在一个错误之后,存储过程中的执行可以继续——没有意识到这会导致一些难以追踪的bug


这种类型的错误处理与Visual Basic 6(以前的.Net)并行。期待SQL Server 2012中的Throw命令。

鉴于您尚未移动到2012,实现原始错误代码冒泡的一种方法是使用从catch块(重新)抛出的异常的文本消息部分。请记住,它可以包含一些结构,例如,调用方代码要在其catch块中解析的XML文本。

在catch块中重新刷新(SQL2012之前的代码,对SQL2012和更高版本使用THROW语句):


当您希望在事务中执行SQL语句并将错误反馈给代码时,还可以为这些场景创建包装存储过程

CREATE PROCEDURE usp_Execute_SQL_Within_Transaction
(
    @SQL nvarchar(max)
)
AS

SET NOCOUNT ON

BEGIN TRY
    BEGIN TRANSACTION
        EXEC(@SQL)
    COMMIT TRANSACTION
END TRY

BEGIN CATCH
    DECLARE @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int
    SELECT @ErrorMessage = N'Error Number: ' + CONVERT(nvarchar(5), ERROR_NUMBER()) + N'. ' + ERROR_MESSAGE() + ' Line ' + CONVERT(nvarchar(5), ERROR_LINE()), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE()
    ROLLBACK TRANSACTION
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState)
END CATCH

GO

-- Test it
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1/0; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'EXEC usp_Another_SP'

@Ashish Gupta:Thx寻求帮助,但我需要将异常从数据库抛出到前端,否则我会打开许多选项,如打印错误号()、返回错误号和1U建议。使用原始错误号和自定义消息抛出异常有什么意义?假设您希望直接在catch块中处理一个或两个特定(预期)错误,并将其余错误留给更高的层。因此,您需要能够重新显示未处理的异常。。。除了@Jenda解释的以外,我还喜欢使用try-catch来确保代码在异常发生后不会继续执行,就像在C#中的do一样:
try{code();}catch(exception exc){log(exc);throw;}finally{cleanup();}
,其中
抛出
将只引发原始异常及其原始上下文。我捕获错误并在SQL中重新抛出自定义错误消息,以添加详细信息,说明发生错误的行或其他详细信息(例如尝试插入的数据)在sql 2012中,您可以使用new THROW关键字Yes重新引发异常。当然,当被问到这个问题时,这是不可用的。更重要的是抓住并抓住它
begin try
    begin transaction;
    
    ...
    
    commit transaction;
end try
begin catch
    declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
    select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
    if @@trancount > 0 rollback transaction;
    raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch
BEGIN TRY
    BEGIN TRANSACTION
    ...
    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION;
    THROW
END CATCH
If @@ERROR > 0
Return
DECLARE
    @ErrorMessage nvarchar(4000) = ERROR_MESSAGE(),
    @ErrorNumber int = ERROR_NUMBER(),
    @ErrorSeverity int = ERROR_SEVERITY(),
    @ErrorState int = ERROR_STATE(),
    @ErrorLine int = ERROR_LINE(),
    @ErrorProcedure nvarchar(200) = ISNULL(ERROR_PROCEDURE(), '-');
SELECT @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 'Message: ' + @ErrorMessage;
RAISERROR (@ErrorMessage, @ErrorSeverity, 1, @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine)
CREATE PROCEDURE usp_Execute_SQL_Within_Transaction
(
    @SQL nvarchar(max)
)
AS

SET NOCOUNT ON

BEGIN TRY
    BEGIN TRANSACTION
        EXEC(@SQL)
    COMMIT TRANSACTION
END TRY

BEGIN CATCH
    DECLARE @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int
    SELECT @ErrorMessage = N'Error Number: ' + CONVERT(nvarchar(5), ERROR_NUMBER()) + N'. ' + ERROR_MESSAGE() + ' Line ' + CONVERT(nvarchar(5), ERROR_LINE()), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE()
    ROLLBACK TRANSACTION
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState)
END CATCH

GO

-- Test it
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1/0; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'EXEC usp_Another_SP'