3

トリガーとでよく知られている問題があり@@IDENTITYます。新しい監査テーブルと、そのテーブルに監査行を挿入するトリガーを作成しました。を使用しているソフトウェアを使用しているため@@IDENTITY、トリガーが新しい行を挿入したときに生成されたIDとの競合が発生しています。を使用しているコードにアクセスできません@@IDENTITY

自分でアイデンティティの価値を生み出すにはどうすればよいかについてのアイデアが必要です。順序が重要なため、GUIDを使用できません。Id列をデフォルト値のdatetime列に置き換えると、GETDATE()一意になることが保証されますか?

ありがとうございました

4

2 に答える 2

4

GETDATE() は一意ではありません。その正確さは、複数のほぼ同時のイベントを同時に提供できるほどのものです。

@@IDENTITY に干渉しないように、独自の ID 値を生成する必要がある場合は、次のことができます...

INSERT INTO
  myTable (
    id,
    field1,
    field2
  )
SELECT
  (SELECT ISNULL(MAX(id), 0) FROM myTable WITH(TABLOCKX)) + 1,
  @p1,
  @p2

これは、それ自体のトランザクション内で暗黙的に行われ、一意の値が保証されます。


編集

私の最初のコメントは、これは複数のレコードを挿入する場合には機能せず、代わりにソース レコードを個別に反復処理して一度に 1 つずつ挿入する必要があるというものでした。

ただし、次の例は、データのセットを処理するのに適している場合があります...

WITH
  sorted_data AS
(
  SELECT
    ROW_NUMBER() OVER (ORDER BY field1) AS set_id,   -- DO NOT include a PARTITION here
    *
  FROM
    inserted
)
INSERT INTO
  myTable (
    id,
    field1,
    field2
  )
SELECT
  (SELECT ISNULL(MAX(id), 0) FROM myTable WITH(TABLOCKX)) + set_id,
  @p1,
  @p2
FROM
  sorted_data

これにより、各行に一意の ID が生成され、同じコードを使用する同時プロセスに対して安全になります。

編集

WITH(TABLOCKX)更新中に他のプロセスがテーブルから読み取らないようにするために追加しました。これにより、並行プロセスが同じ MAX(id) を確立してから、新しいレコードに重複する ID を挿入しようとするのを防ぎます。

(単一のクエリ構造により、レコードが読み取られた後にレコードが変更されることは既に防止されていましたが、MAX(id) が読み取られてからすべての新しいレコードが挿入された「間」で、他のプロセスがテーブルから読み取りを行うことは防止されませんでした。)

于 2011-10-31T15:44:06.570 に答える
1

変更できない可能性が高いことは承知していますが、問題は、ソフトウェアが範囲外の @@IDENTITY を使用していることです。ANY テーブルに挿入すると、@@IDENTITY が変更されます。ソフトウェアは、代わりに関数 scope_identity() を使用する必要があります。

于 2011-10-31T17:29:22.887 に答える