【问题标题】:How to return error with OUTPUT SQL 2008?如何使用 OUTPUT SQL 2008 返回错误?
【发布时间】:2019-01-30 01:39:53
【问题描述】:

您好,我有一个使用 try/catch 块执行简单插入事务的存储过程。如果事务成功OUTPUT 将返回插入的记录 ID。如果发生错误,我想从 try/catch 块返回内容。在发生错误的情况下,我当前的代码将返回空白 RecID。这是我的代码示例:

CREATE PROCEDURE [dbo].[InsertRecord] 
    @Status BIT = NULL,
    @Name VARCHAR(50) = NULL,
    @Code CHAR(2) = NULL,
    @ActionID UNIQUEIDENTIFIER = NULL
AS
    SET NOCOUNT ON
    SET XACT_ABORT ON
    BEGIN TRY
        BEGIN
            INSERT INTO dbo.Dictionary(
                Status,Name,Code,ActionDt,ActionID
            )
            OUTPUT INSERTED.RecID
            VALUES(
                @Status,@Name,@Code,CURRENT_TIMESTAMP,@ActionID
            );
        END
    END TRY
    BEGIN CATCH 
        SELECT  
            ERROR_PROCEDURE() AS ErrorProcedure,
            ERROR_LINE() AS ErrorLine,
            ERROR_NUMBER() AS ErrorNumber,
            ERROR_MESSAGE() AS ErrorMessage,
            CURRENT_TIMESTAMP AS DateTime
    END CATCH

如果我尝试插入已经存在的相同记录,上面的代码将返回以下代码:

ErrorProcedure  
InsertRecord    
ErrorLine   
16              
ErrorNumber 
2627
ErrorMessage    
Violation of PRIMARY KEY constraint 'PK_Code'. Cannot insert duplicate key in object 'dbo.Dictionary'. The duplicate key value is (44).
DateTime
2018-08-23 10:46:02.920

这是我所期望的,这在 Management Studio 2008 中显示。当我使用 ColdFusion 调用此过程时,我只得到RecID = ''。这是我如何调用此过程的示例:

<cftry>
    <cfstoredproc procedure="InsertRecord" datasource="#dsn#">
        <cfprocparam dbvarname="@Status" value="#trim(arguments.frm_status)#" cfsqltype="cf_sql_bit" />
        <cfprocparam dbvarname="@Code" value="#trim(arguments.frm_code)#" cfsqltype="cf_sql_char" maxlength="2" null="#!len(trim(arguments.frm_code))#" />
        <cfprocparam dbvarname="@Name" value="#trim(arguments.frm_name)#" cfsqltype="cf_sql_varchar" maxlength="50" null="#!len(trim(arguments.frm_name))#" />
        <cfprocparam dbvarname="@ActionID" value="#trim(SESSION.UserID)#" cfsqltype="cf_sql_idstamp" maxlength="50" null="#!len(trim(SESSION.UserID))#" />
        <cfprocresult name="Result"/>
    </cfstoredproc>

    <cfset local.fnResults = {status : "200", RecID : Result.RecID}>

    <cfcatch type="any">
        <cfset local.fnResults = {error:cfcatch,status : "400", class : "alert-danger", message : "Error! Please contact your administrator."}>
    </cfcatch>
</cftry>

有没有办法在执行后将错误从存储过程返回给 CodlFusion?

【问题讨论】:

  • 在 cfstoredproc 调用之后转储 Result 变量会得到什么? &lt;cfdump var="#Result#"&gt; 错误可能存储在该结构中的某个其他变量名下。
  • @Miguel-F Just RecID 空白没有价值。
  • 这似乎不对。结果变量应该是一个包含来自存储过程调用的其他信息的结构。状态、执行时间等。请注意,如果存储过程返回多个结果集,那么您需要为每个结果集编写一个 cfprocresult 标签。
  • @Miguel-F 这就是我的想法,但如果我转储结果,则没有其他信息......我的程序看起来与上面的相同。

标签: sql sql-server-2008 stored-procedures coldfusion


【解决方案1】:

您的代码实际上与您编写的代码完全一样。它正在捕获错误并在CATCH 块中输出您的数据。如果您想捕获特定类型的错误并以不同方式处理它,那么您必须指定它。 2627 是您的主键约束违规错误,但我不确定您是否要将其视为实际错误。最好先看看你的主键是否存在。

尝试类似:

CREATE PROCEDURE [dbo].[InsertRecord] 
    @Status BIT = NULL,
    @Name VARCHAR(50) = NULL,
    @Code CHAR(2) = NULL,
    @ActionID UNIQUEIDENTIFIER = NULL
AS
    SET NOCOUNT ON
    SET XACT_ABORT ON
        /* Check if your primary key record exists. */
        IF EXISTS(SELECT 1 FROM dbo.Dictionary WHERE ActionID = @ActionID) 
          /* Instead of ActionID, use whatever your Primary Key is. */
        BEGIN
            SELECT NULL ;  /* This returns NULL if the primary key record exists. */
        END
        ELSE
        /* PK record does not exist, so try to INSERT. */
        BEGIN TRY
            INSERT INTO dbo.Dictionary(
                Status,Name,Code,ActionDt,ActionID
            )
            OUTPUT INSERTED.RecID
            VALUES(
                @Status,@Name,@Code,CURRENT_TIMESTAMP,@ActionID
            );
        END TRY
        BEGIN CATCH /* INSERT errored, so return the data of what it was. */
            SELECT  
                ERROR_PROCEDURE() AS ErrorProcedure,
                ERROR_LINE() AS ErrorLine,
                ERROR_NUMBER() AS ErrorNumber,
                ERROR_MESSAGE() AS ErrorMessage,
                CURRENT_TIMESTAMP AS DateTime
        END CATCH

https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=9601e1c43d38ef551f23f2c866e50b5d

注意:要捕获特定的错误代码(您必须找到要查找的错误代码),请使用以下内容:

BEGIN CATCH
  IF ERROR_NUMBER() = 2627  /* This is a PK Violation error */
    /* DO YOUR PK VIOLATION STUFF HERE. */
END CATCH

【讨论】:

  • 另请注意,您可能需要围绕该过程执行一些 SQL 锁定。
  • 我想我误读了您最初的问题。您的 sproc 似乎没有分配 OUTPUT 变量,因此不会填充 Result.RecID,因为在 PK Violation 上没有插入任何内容。我猜INSERT ...OUTPUT INSERTED.... 在这种情况下仍然会从存储过程中泄漏出来。我回家后会尝试做一些测试。
  • 我想将错误返回到服务器端语言,如果存在错误,请向用户发送一条消息,就像我的 try catch 块中有一条消息一样。可能有更好的方法来处理这个问题,但我有验证来防止这种错误。 Pk 违规只是一个例子。我不确定在表中插入错误是否是一个不错的选择?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-02
  • 1970-01-01
相关资源
最近更新 更多