0

Repeatable Read Isolation Level を使用してトランザクションに取り組んでいます。このトランザクションに、Try-Catch とエラー ハンドラーの両方の機能を組み込みたいと考えています。コードを実行すると、次のようなエラー メッセージが表示されます: Msg 102, Level 15, State 1, Line 18 Incorrect syntax near 'BEGIN'. メッセージ 102、レベル 15、状態 1、行 23 '@errnum' 付近の構文が正しくありません。

このトランザクションを正常に完了するにはどうすればよいですか? または、このトランザクションを記述する正しい方法は何ですか?

これは今の私の仕事です:

CREATE PROCEDURE ItemFlow (@Name  VARCHAR(50),
                                @aPrice  MONEY,
                                @bPrice MONEY)
AS
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
GO
  BEGIN TRAN
      IF EXISTS (SELECT 1
                 FROM   Cashier
                 WHERE  Item = '@Item')
        UPDATE Cashier
        SET    bPrice = '@bPrice',
               aprice = '@aprice'
        WHERE  Item = '@Item'
      ELSE
        INSERT INTO Cashier
                    (Item, aPrice, bPrice)
        VALUES      ('@Item', '@aPrice', '@bPrice')
                     END
BEGIN TRY
    EXECUTE ItemFlow
END TRY

BEGIN CATCH
    @errnum = ERROR_NUMBER(),
           @severity = ERROR_SEVERITY(),
           @errstate = ERROR_STATE(),
           @proc = ERROR_PROCEDURE(),
           @line = ERROR_LINE(),
           @message = ERROR_MESSAGE()

END CATCH
4

3 に答える 3

1

提案された変更を実装する前に、次の質問に答えてください。1) proc 内で proc 自体を呼び出す理由は何ですか? 2) なぜ ERROR_ 関数を変数に設定しているのですか? それらを使用しますか?そうでない場合は、変数を宣言する必要はありません。

また:

  • 明らかに、GOはこれの一部になることはできません. これは、SSMS の単なるバッチ区切りです。

  • 使用されていないという入力パラメーターと、宣言されていない@Nameという変数があります。@Itemそれらは同じものだと思われる@Itemので、代わりに入力パラメーターとして使用しました@Name

  • 3 つのクエリで入力パラメーターを文字列リテラルとして使用していますが、これは意味がありません。変数として機能できるように、それらを囲む一重引用符を削除する必要があります。

  • また、トランザクションから TRY / CATCH ロジックを分離しないでください。

無限ループ (停止する条件なしで自分自身を呼び出す proc) を呼び出すことに本当の意図がないと仮定すると、コードは次のようになります。

CREATE PROCEDURE ItemFlow
(
  @Item  VARCHAR(50),
  @aPrice  MONEY,
  @bPrice MONEY
)
AS
SET NOCOUNT ON;

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

BEGIN TRY

  BEGIN TRAN

  IF EXISTS (SELECT 1
             FROM   Cashier
             WHERE  Item = @Item)
  BEGIN
        UPDATE Cashier
        SET    bPrice = @bPrice,
               aprice = @aPrice
        WHERE  Item = @Item;
  END;
  ELSE
  BEGIN
        INSERT INTO Cashier
                    (Item, aPrice, bPrice)
        VALUES      (@Item, @aPrice, @bPrice);
  END;

  COMMIT TRAN;

END TRY
BEGIN CATCH

  IF (@@TRANCOUNT > 0)
  BEGIN
    ROLLBACK TRAN;
  END;

  THROW;

END CATCH;

THROWは SQL Server 2012 で導入されました。2005 ~ 2008 R2 のものを使用している場合は、次のものに置き換えますTHROW

DECLARE @ErrMessage NVARCHAR(4000);
SET @ErrMessage = ERROR_MESSAGE();
RAISERROR(@ErrMessage, 16, 1);
RETURN;
于 2015-01-10T18:15:10.100 に答える
0

あなたのコードにはいくつかの問題があります:

BEGIN付近のエラー

GOバッチセパレーターです。これは有効な T-SQL ではなく、SSMS によってのみ理解されます。実質的に 2 つのクエリを送信しています。

CREATE PROCEDURE ItemFlow (@Name  VARCHAR(50),
                                @aPrice  MONEY,
                                @bPrice MONEY)
AS
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

と:

BEGIN TRAN
...

ご覧のとおり、ストアド プロシージャの本体は空です。これを取り除くために削除GOします。

@errnum付近のエラー

変数が宣言されていません。また、これらの変数に値を割り当てるには、SELECTまたはを使用する必要があります。SET

DECLARE @errnum int,
        @serverity int,
        (etc.)
        
SELECT @errnum = ERROR_NUMBER(),
       @severity = ERROR_SEVERITY(),
       @errstate = ERROR_STATE(),
       @proc = ERROR_PROCEDURE(),
       @line = ERROR_LINE(),
       @message = ERROR_MESSAGE()

最後に一つだけ:

がありますが、BEGIN TRANありませんCOMMIT TRAN。sproc の実行が終了しても、トランザクションはまだ開いています。

于 2015-01-10T17:59:20.590 に答える