2

uniqueidentifiers を使い始めたところ、予期しない問題が発生しました。

まず第一に、通常は SCOPE_IDENTITY() を使用しますが、uniqueidentifier ではこれができなくなりましたが、概念上はデフォルト (newid() または newsequentialid()) の結果として自動生成された id 値が含まれます。 ) 制約。

INSERT ステートメントで OUTPUT 句を使用して、UUID をテーブル変数に出力することにしました。考えてみると、OUTPUT 句は SCOPE_IDENTITY を時代遅れにしています。これは、同じことやそれ以上のことを達成するためのより明確で強力な方法であるためです (たとえば、挿入されたすべての行に対して複数の自動生成された列に明確かつ直接アクセスできます)。

ただし、OUTPUT を使用すると、通常は挿入に続く @@rowcount のテストにどのように影響するのか疑問に思っています。@@rowcount は、メイン ステートメントに挿入された行数または出力句によってテーブル変数に挿入された行数を反映しますか?

違いはないと思うかもしれませんが (つまり、どちらの方法でもカウントは同じでなければなりません)、違いはあります。なぜなら、挿入ステートメントが失敗した場合でも、OUTPUT 句は値を返し、テーブルにデータを入力するとドキュメントに記載されているからです。 .

OUTPUT 句を持つ UPDATE、INSERT、または DELETE ステートメントは、ステートメントでエラーが発生してロールバックされた場合でも、クライアントに行を返します。ステートメントの実行時にエラーが発生した場合は、結果を使用しないでください。

特に@@rowcountは、OUTPUTを使用する場合にのみ最も外側のステートメントを常に反映することに言及していますが、これはネストされたクエリのコンテキストであると言及しています。私の場合の OUTPUT 句は最も外側のステートメントの一部であるため、insert ステートメントが失敗した場合に @@rowcount が出力テーブルに挿入された行数を報告するかどうかは不明です。

    declare @new_uuid TABLE (ID uniqueidentifier);
    insert into Users (ID, PersonID, Username, Password, Notes, Enabled)
    output INSERTED.UUID into @new_uuid
        values (@id, @personid, @username, @password, @notes, @enabled )
    if (@@rowcount <> 1) goto fail; --does this reflect rows inserted into Users or @new_uuid?  What if the insert fails, and rows are still output to @new_uuid?
4

1 に答える 1

3

次の TSQL コードを使用して、この動作を実験的にテストしました。

create function NEWOBJECTID() returns int as begin return 1 / 0; end --function that would typically perform work to create a new object id, but intentionally throws an error instead
go

declare @uuidtable table (UUID uniqueidentifier);

insert into Users (ID)
output INSERTED.UUID into @uuidtable --UUID column has default constraint of (newid())
values (dbo.NEWOBJECTID()); --value to insert will throw an error

print @@rowcount; --called immediately after statement to see how it was affected by the failure
select * from @idtable; --see if anything was output into the table variable

このステートメントの結果は、@@rowcount がゼロを返し、@uuidtable 変数にゼロ行が存在するというものでしたが、この結果は誤解を招くため、読み続けてください。

最初に、これにより、行が挿入されていないため、出力が発生しないと信じるようになりました。これは誤りであり、簡単な修正でそれが証明されます。

insert into Users (ID)
output INSERTED.UUID into @uuidtable --UUID column has default constraint of (newid())
values
(1), --value to insert should succeed
(2), --value to insert should succeed
(dbo.NEWOBJECTID()); --value to insert will throw an error

今回実行すると、@@rowcount はまだゼロです。ただし、2 つの新しい uniqueidentifiers を持つ 2 つの行が @uuidtable に出力されました。

これは、最初の 2 つの値が正常に挿入されて @uuidtable に出力されたにもかかわらず、エラーの結果としてステートメント全体がロールバックされたため、@@rowcount が挿入された最終的な行数 (ゼロ) を反映していることを示しています。

2 つの行が OUTPUT テーブルに挿入されましたが、ステートメントが失敗した結果として最終的に挿入された行はゼロであり、@@rowcount はゼロを報告しているため、数ではなく挿入ステートメント自体によって挿入された行数を反映していることを証明しています。途中で OUTPUT テーブルに挿入された行の数。これは、ステートメント全体が失敗した場合でも、行が OUTPUT になるというドキュメントの内容も確認します。

于 2013-11-07T21:26:09.847 に答える