1

ストアドプロシージャの仕様は次のとおりです。テーブルから
を選択して返すには(順序は重要ではなく、見つかった上位1つだけで十分です)、そのレコードを選択したらすぐに、選択されないようにマークを付ける必要があります。また。Idtb_r12028dxi_SandpitConsoleProofClient'P'

ストアドプロシージャは次のとおりです。

ALTER PROCEDURE [dbo].[r12028dxi_SandpitConsoleProofSweep]
    @myId INT OUTPUT
AS

/*
DECLARE @X INT
EXECUTE [xxx].[dbo].[r12028dxi_SandpitConsoleProofSweep] @X OUTPUT
SELECT @X
*/

DECLARE @NumQueue INT = (
            SELECT [cnt] = COUNT(*) 
            FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient
            WHERE [Status] IS NULL
            );
IF @NumQueue > 0 
    BEGIN

        BEGIN TRANSACTION;

        DECLARE @foundID INT = (SELECT TOP 1 Id FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient WHERE [Status] IS NULL);

        UPDATE x
        SET x.[Status] = 'P'
        FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient x
        WHERE x.Id = @foundID 

        SET @myId = @foundID;

        RETURN;

        COMMIT TRANSACTION;

    END;
GO

次のエラーメッセージが返されます。

EXECUTE後のトランザクション数は、BEGINステートメントとCOMMITステートメントの数が一致していないことを示しています。以前のカウント=0、現在のカウント=1。

Updateスクリプトを追加したところですが、BEGIN TRANSACTION;そのCOMMIT TRANSACTION;前は次のようになったら問題なく動作しました...

ALTER PROCEDURE [dbo].[r12028dxi_SandpitConsoleProofSweep]
    @myId INT OUTPUT
AS

/*
DECLARE @X INT
EXECUTE [xxx].[dbo].[r12028dxi_SandpitConsoleProofSweep] @X OUTPUT
SELECT @X
*/

DECLARE @NumQueue INT = (
            SELECT [cnt] = COUNT(*) 
            FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient
            WHERE [Status] IS NULL
            );
IF @NumQueue > 0 
    BEGIN


    SELECT TOP 1 @myId = Id FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient;
    RETURN;


    END;
GO

BEGIN TRANSACTION;/を追加したのCOMMIT TRANSACTION;は、データが出力変数に読み込まれ、UPDATEが実行されるようにするためです。手順のこのセクションを省略すべきですか?

4

3 に答える 3

5

あなたは「RETURN」を持っています。「COMMITTRANSACTION」の前。これは「COMMITTRANSACTION」を意味します。実行されることはありません。

于 2013-01-06T23:39:12.457 に答える
2

@Andrew Bickertonによる完全に合理的な提案の代わりに、次のようなCTEROW_NUMBER()関数を使用することもできます。

WITH ranked AS (
  SELECT
    Id,
    [Status],
    rnk = ROW_NUMBER() OVER (ORDER BY Id)
  FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient
  WHERE [Status] IS NULL
)
UPDATE ranked
SET
  [Status] = 'P',
  @myId = Id
WHERE rnk = 1
;

このROW_NUMBER()関数は、すべての行にランキングを割り当てます[Status] IS NULL。これにより、特定の行のみを更新できます。

この場合、CTEは1つのテーブルから行をプルするだけなので、UPDATEステートメントの直接のターゲットとしてCTEを使用することは絶対に正当です。(これは、UPDATEステートメントでのビューの使用に似ています。)

于 2013-01-07T15:06:49.777 に答える
2

あなたが望むものを与えてください:

そのレコードを選択したらすぐに、再度選択されないように「P」のマークを付ける必要があります。

あなたは単一のステートメントでそれを達成することができます(そしてトランザクションではありません)

ALTER PROCEDURE [dbo].[r12028dxi_SandpitConsoleProofSweep]
    @myId INT OUTPUT
AS
BEGIN
    UPDATE x
        SET x.[Status] = 'P',
            @myID = x.ID
        FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient x
        /* a sample join to get your single row in an update statement */
        WHERE x.ID = (SELECT MIN(ID)
                      FROM xxx.DBO.tb_r12028dxi_SandpitConsoleProofClient sub
                      WHERE ISNULL(sub.[Status], '') != 'P')
END

注:並行処理(つまり、2つのスレッドが単一のキューから選択しようとする)を処理する場合、単一のトランザクション内で実行するよりも、ロックの動作が重要になります。

于 2013-01-07T09:45:50.850 に答える