-1

次のように、データベースに 3 つのテーブルがあるとします。

  • Person( personid, ...) --- これはエンティティでpersonidあり、ID 列です
  • Phone( phoneid, ...) --- これはエンティティでphoneidあり、ID 列です
  • PersonPhone( personid, phoneid) ---この関係

テーブルにデータを挿入するときは、最初にエンティティ テーブルに行を挿入し、生成された を取得してidから、関係テーブルに行を挿入する必要があります。

それはうまくいっています。質問: 次のTry Catchようなステートメントを含むトランザクションを含むストアド プロシージャがあります。

BEGIN TRY
declare aCursor cursor local fast_forward for (Select Query...)

open aCursor;
fetch next from aCursor into @variables....

while @@fetch_status = 0
begin

   INSERT INTO Person(...);
   set @personid =@@IDENTITY;

   INSERT INTO Phone(...);
   set @phoneid =@@IDENTITY;

   INSERT INTO PersonPhone(@personid, @phoneid);       
end; 

END TRY
BEGIN CATCH
    close aCursor;
    deallocate selectdistributor;
     SELECT ERROR_NUMBER() AS ErrorNumber,ERROR_MESSAGE() AS ErrorMessage;    
    ROLLBACK TRAN;
    RETURN;
END CATCH  
COMMIT;  
close aCursor;
deallocate aCursor;

カーソルを使用すると、人、電話のレコードが挿入されます。SP を実行すると、リレーションシップへの最初のデータ挿入で停止します。また、正しい @personid、@phoneid を取得できますが、トランザクションが完了する前に、INSERT INTO PersonPhone(@personid, @phoneid); でエラーが発生します。なので:

INSERT ステートメントが FOREIGN KEY 制約 "Person_PersonPhone_FK1" と競合しました。データベース「MYDB」、テーブル「dbo.Person」、列「PersonID」で競合が発生しました。

システムによって生成された ID が、トランザクションが完了する前に認識されなかったようです。

この問題を解決するにはどうすればよいですか?

4

1 に答える 1

0

おそらく問題は、@@identity を使用したことです。これは、この目的で決して使用されるべきではありません。テーブルの 1 つにトリガーがある場合、間違った値 (トリガーが挿入されているテーブルからの ID) を返す可能性があり、その値は偶然にも外部キーがリンクするテーブルに存在しません。

したがって、ID を持つ監査テーブルに挿入する最初のテーブルにトリガーがあるとします。レコードは 1234 の ID で挿入されます。ただし、トリガが別のテーブルに挿入されるため、@@Identity によって返される値は元のテーブルに存在しない 5678 です。最初のテーブルに戻る FK を使用してテーブルに挿入しようとすると、値 5678 が最初のテーブルに存在しないため、エラー メッセージが表示されます。

代わりに OUTPUT 句を使用してください。scope_identity() を使用することもできますが、出力はより柔軟です (また、複数のレコードを挿入して、すべての ID と、レコードを一意に識別する可能性のある他のフィールドを受け取ることができます。

そして、私はアーロンと一緒です。誰かが私の命を脅かさない限り、これにはカーソルを使用しません.

于 2013-04-22T19:00:16.687 に答える