0

SQL Server ストアド プロシージャの句からデータベース エラーで構成される結果セットを返す必要がありますがCATCH、それで行き詰まっています。結果セットを返すためにカーソルを使用する必要がありますか? その場合OUTPUT、.NET アプリケーションのパラメーターの型宣言は何ですか? 試しObjectてみVariantましたが、うまくいきませんでした。

また、ステートメントを使用して返す簡単な方法も試しましたSELECTが、あるストアドプロシージャでは機能しますが、別のストアドプロシージャでは機能しませんCATCH

 while (@I <= @count)
 begin      
    BEGIN TRY       
        -- delete all previous rows inserted in @customerRow for previous counts @I     
        delete from @customerRow

        -- this is inserting the current row that we want to save in database
        insert into @customerRow 
           SELECT  
               [id],[firstname], [lastname], [street], [city],
               [phone],[mobile],[fax], [email], [companyName],
               [licence],[brn], [vat], [companyStreet], [companyCity], [status]
           FROM 
               (SELECT  
                   ROW_NUMBER() OVER (ORDER BY id ASC) AS rownumber,
                   [id], [firstname], [lastname], [street], [city],
                   [phone], [mobile], [fax], [email], [companyName],
                   [licence], [brn], [vat], [companyStreet], [companyCity], [status]
                FROM    
                   @registerDetails) AS foo
          WHERE 
             rownumber = @I                                             

       -- this stored procedure handles the saving of the current customer row just defined above
        -- if there is any error from that sproc, it will jump to CATCH block 
        --save the error message in the temp table and continue 
        --with the next customer row in the while loop.
        exec dbo.sp_SaveCustomer @customerRow
    END TRY
    BEGIN CATCH
        IF @@TranCount = 0
        -- Transaction started in procedure.
        -- Roll back complete transaction.
        ROLLBACK TRANSACTION;
        if XACT_STATE()= -1 rollback transaction

        DECLARE @ErrorMessage NVARCHAR(4000);
        DECLARE @ErrorSeverity INT;
        DECLARE @ErrorState INT;


        SELECT @ErrorMessage = ERROR_MESSAGE() + ' ' + (select firstname from @registerDetails where id=@I)
        SELECT @ErrorSeverity = ERROR_SEVERITY();
        SELECT @ErrorState = ERROR_STATE() 

        INSERT INTO #registrationResults (error,id)
        SELECT @ErrorMessage, @I 

    END CATCH       

    set @I = @I +1              
end 
COMMIT TRANSACTION registerTran

select * from #registrationResults

上記は、vb.net コードで次のように呼び出すと、1 つのストアド プロシージャで機能します。

ta.Fill(registrationErrors, clientDetailsDT)

whereregistrationErrorsclientDetailsDTは厳密に型指定されたデータ テーブルです。

これはしません:

    begin catch
    IF @@TranCount > 0 or XACT_STATE()= -1 ROLLBACK TRANSACTION;
    DECLARE @ErrorMessage NVARCHAR(4000);
    DECLARE @ErrorSeverity INT;
    DECLARE @ErrorState INT;
    DECLARE @ErrorLine INT;


    SELECT @ErrorMessage = ERROR_MESSAGE();
    SELECT @ErrorSeverity = ERROR_SEVERITY();
    SELECT @ErrorState = ERROR_STATE();
    SELECT @ErrorLine = ERROR_Line();

    ****ERROR -- THIS SELECT WAS MESSING ALL UP as it was this select that was being        returned to the .NET and not the select of the desired #temp table after, hence returning 0    resultset as this select was EMPTY. !!  
    select status_indicator from InsertInvoiceTriggerData where session_GUID =   guid**
    delete from InsertInvoiceTriggerData where session_GUID = @guid**

    INSERT INTO #registrationResults (error,id)
    SELECT @ErrorMessage, NULL

    select * from #registrationResults

end catch

結果セットを返す方法について何か提案はありますか?

4

1 に答える 1

1

私はあなたのデータベース コードを見たことがありませんが、私の経験ではcatch、トランザクション全体をロールバックする必要があるという意味で最初のエラーが発生しました。他のこととは別に、これは、特定の状況で返されるエラーが 1 つしかないことも意味します。

そのため、ストアド プロシージャで 2 つのスカラー出力パラメーターを使用します。

@Error int = null output,
@Message nvarchar(2048) = null output

そして、他の出力変数と同じようにそれらを取得できます。

UPD:コードを追加した後でも、問題が何であるかを正確に理解できません。ただし、あなたのコードにはいくつかの問題があるので、それらを指摘します。そのうちの 1 つが問題を解決する可能性があります。最後のスニペットは不完全すぎるため、最初のスニペットのみコメントします。

  • ループの前のどこかで最も外側のトランザクションを開始する必要があります。そうでない場合、コードは失敗します。
  • 私の推測が正しければ、dbo.sp_SaveCustomerストアド プロシージャ内にすべてのセーブポイント ロジックを実装しました。save tranそうでない場合、あなたが示したコードにはorrollback @savepointステートメントがないため、議論全体は無意味です。
  • 最初のcatchステートメント -IF @@TranCount = 0 ROLLBACK TRANSACTIONすべてが間違っています。条件が成功した場合、存在しないトランザクションをロールバックしようとしてエラーが発生します。セーブポイントに依存している場合は、ここにいるべきではありません。
  • その次は無条件の中断になるはずです: if XACT_STATE()= -1 begin rollback transaction; break; end;
  • キャッチ コードの残りの部分は、次のように置き換えることができます。 INSERT INTO @registrationResults (error, id) SELECT error_message() + ' ' + firstname, id from @registerDetails where id=@I;
  • また、ロールバックも影響するため、この目的で一時テーブルを使用しないでください。これには常にテーブル変数を使用します。これらは非トランザクションです (他の変数と同様)。
  • このcommit時点でコミットするトランザクションがない可能性があるため、これは条件付きである必要があります。 if @@trancount > 0 commit tran;
  • ステートメントでセーブポイント名を指定しても意味がありcommitません。混乱を招くだけです (ただし、エラーとは見なされません)。また、このモジュールにはセーブポイントがあってはなりません (ループの前に定義していない限り)。

dbo.SaveCustomerストアド プロシージャ内で実際に何が起こっているかはわかりませんので、これは氷山の一角に過ぎないと思います。

UPD2:ストアド プロシージャからレコードセットを受け取るために使用する VB.NET コードのサンプルを次に示します。

Private Function SearchObjectsBase( _
    SearchMode As penum_SEARCH_MODE, SearchCriteria As String
) As DataSet

Dim Cmd As DbCommand, Pr As DbParameter, dda As DbDataAdapter

' Initialise returning dataset object
SearchObjectsBase = New DataSet()

Cmd = MyBase.CreateCommand(String.Format("dbo.{0}", SearchMode))

With Cmd

    ' Parameter definitions
    Pr = .CreateParameter()
    With Pr
        .ParameterName = "@SearchCriteria"
        .DbType = DbType.Xml
        .Value = SearchCriteria
    End With
    .Parameters.Add(Pr)

    ' Create data adapter to use its Fill() method
    dda = DbProviderFactories.GetFactory(.Connection).CreateDataAdapter()
    ' Assign the prepared DbCommand as a select method for the adapter
    dda.SelectCommand = Cmd

    ' A single resultset is expected here
    dda.Fill(SearchObjectsBase)

End With

' Set error vars and get rid of it
Call MyBase.SetErrorOutput(Cmd)

' Check for errors and, if any, discard the dataset
If MyBase.ErrorNumber <> 0 Then SearchObjectsBase.Clear()

End Function

私は .NET 4.5 を使用しています。これには、実際の接続に基づいて最適なデータ アダプターを自動的に選択する非常に優れた方法があります。そして、この関数の呼び出しは次のとおりです。

Dim XDoc As New XElement("Criteria"), DS As DataSet = Nothing, DT As DataTable
...
DS = .SearchPatients(XDoc.ToString(SaveOptions.None))
' Assign datasource to a grid
Me.dgr_Search.DataSource = DS.Tables.Item(0)

ここで、SearchPatients() は SearchObjectsBase() の上のラッパーです。

于 2014-11-28T00:33:33.127 に答える