1280

IDENTITY挿入された行を取得する最良の方法は何ですか?

@@IDENTITYand IDENT_CURRENTandについては知ってSCOPE_IDENTITYいますが、それぞれに付随する長所と短所がわかりません。

誰かが違いと、それぞれをいつ使用すべきかを説明してもらえますか?

4

14 に答える 14

1615
  • @@IDENTITYすべてのスコープにわたって、現在のセッションの任意のテーブルに対して生成された最後の ID 値を返します。 スコープをまたいでいるので、ここは注意が必要です。現在のステートメントではなく、トリガーから値を取得できます。

  • SCOPE_IDENTITY()現在のセッションと現在のスコープで任意のテーブルに対して生成された最後の ID 値を返します。 一般的に使用したいもの

  • IDENT_CURRENT('tableName')任意のセッションおよび任意のスコープで特定のテーブルに対して生成された最後の ID 値を返します。これにより、上記の2つが必要なものではない場合に備えて、値を取得するテーブルを指定できます(非常にまれです)。また、@ Guy Starbuckが述べたように、「レコードを挿入していないテーブルの現在の IDENTITY 値を取得する場合は、これを使用できます。」

  • ステートメントのOUTPUTにより、そのINSERTステートメントを介して挿入されたすべての行にアクセスできます。特定のステートメントにスコープが設定されているため、上記の他の関数よりも簡単です。ただし、これはもう少し冗長で (テーブル変数/一時テーブルに挿入してからクエリを実行する必要があります)、ステートメントがロールバックされるエラー シナリオでも結果が得られます。つまり、クエリで並列実行プランが使用されている場合、これがID を取得するための保証された唯一の方法です (並列処理をオフにする以外は)。ただし、トリガーの前に実行されるため、トリガーによって生成された値を返すために使用することはできません。

于 2008-09-03T21:38:23.863 に答える
206

挿入されたIDを取得する最も安全で正確な方法は、output句を使用することだと思います。

たとえば(次のMSDN記事から引用)

USE AdventureWorks2008R2;
GO
DECLARE @MyTableVar table( NewScrapReasonID smallint,
                           Name varchar(50),
                           ModifiedDate datetime);
INSERT Production.ScrapReason
    OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
        INTO @MyTableVar
VALUES (N'Operator error', GETDATE());

--Display the result set of the table variable.
SELECT NewScrapReasonID, Name, ModifiedDate FROM @MyTableVar;
--Display the result set of the table.
SELECT ScrapReasonID, Name, ModifiedDate 
FROM Production.ScrapReason;
GO
于 2011-05-20T14:43:54.040 に答える
124

私は他の人たちと同じことを言っているので、誰もが正しいです.私はそれをより明確にしようとしています.

@@IDENTITYクライアントのデータベースへの接続によって最後に挿入されたものの ID を返します。
ほとんどの場合、これで問題なく動作しますが、トリガーによって、知らない新しい行が挿入され、目的の行ではなく、この新しい行から ID が取得されることがあります。

SCOPE_IDENTITY()この問題を解決します。データベースに送信した SQL コードに最後に挿入したものの ID を返します。トリガーが実行されて余分な行が作成されても、間違った値が返されることはありません。万歳

IDENT_CURRENT誰かによって挿入された最後の ID を返します。他のアプリが偶然に別の行を挿入した場合、自分の行の代わりにその行の ID を取得します。

安全にプレイしたい場合は、常に を使用してSCOPE_IDENTITY()ください。そのままに@@IDENTITYしておくと、誰かが後でトリガーを追加することを決定した場合、すべてのコードが壊れます。

于 2008-09-03T21:44:50.060 に答える
72

新しく挿入された行の ID を取得する最良の (最も安全な) 方法は、次のoutput句を使用することです。

create table TableWithIdentity
           ( IdentityColumnName int identity(1, 1) not null primary key,
             ... )

-- type of this table's column must match the type of the
-- identity column of the table you'll be inserting into
declare @IdentityOutput table ( ID int )

insert TableWithIdentity
     ( ... )
output inserted.IdentityColumnName into @IdentityOutput
values
     ( ... )

select @IdentityValue = (select ID from @IdentityOutput)
于 2013-04-29T07:22:55.720 に答える
23

MSDN から

@@IDENTITY、SCOPE_IDENTITY、および IDENT_CURRENT は、テーブルの IDENTITY 列に挿入された最後の値を返すという点で類似した関数です。

@@IDENTITY と SCOPE_IDENTITY は、現在のセッションの任意のテーブルで生成された最後の ID 値を返します。ただし、SCOPE_IDENTITY は現在のスコープ内でのみ値を返します。@@IDENTITY は特定のスコープに限定されません。

IDENT_CURRENT はスコープとセッションによって制限されません。指定されたテーブルに限定されます。IDENT_CURRENT は、任意のセッションおよび任意のスコープで特定のテーブルに対して生成された ID 値を返します。詳細については、IDENT_CURRENT を参照してください。

  • IDENT_CURRENT は、テーブルを引数として取る関数です。
  • テーブルにトリガーがある場合、@@IDENTITY は紛らわしい結果を返すことがあります。
  • ほとんどの場合、SCOPE_IDENTITY はあなたのヒーローです。
于 2008-09-03T21:37:02.137 に答える
22

Entity Framework を使用すると、内部的にOUTPUT手法を使用して、新しく挿入された ID 値を返します。

DECLARE @generated_keys table([Id] uniqueidentifier)

INSERT INTO TurboEncabulators(StatorSlots)
OUTPUT inserted.TurboEncabulatorID INTO @generated_keys
VALUES('Malleable logarithmic casing');

SELECT t.[TurboEncabulatorID ]
FROM @generated_keys AS g 
   JOIN dbo.TurboEncabulators AS t 
   ON g.Id = t.TurboEncabulatorID 
WHERE @@ROWCOUNT > 0

出力結果は一時テーブル変数に格納され、テーブルに結合され、テーブルから行の値が返されます。

注: EF がエフェメラル テーブルを実際のテーブルに内部結合する理由がわかりません (どのような状況で 2 つが一致しないのでしょうか)。

しかし、それが EF の機能です。

この手法 ( OUTPUT) は、SQL Server 2008 以降でのみ使用できます。

編集- 参加の理由

Entity Framework が単に値を使用するのではなく、元のテーブルに結合する理由OUTPUTは、EF もこの手法を使用しrowversionて新しく挿入された行を取得するためです。

次の属性を使用して、エンティティ フレームワーク モデルでオプティミスティック コンカレンシーを使用できます。Timestamp

public class TurboEncabulator
{
   public String StatorSlots)

   [Timestamp]
   public byte[] RowVersion { get; set; }
}

これを行うと、Entity Framework はrowversion新しく挿入された行のを必要とします。

DECLARE @generated_keys table([Id] uniqueidentifier)

INSERT INTO TurboEncabulators(StatorSlots)
OUTPUT inserted.TurboEncabulatorID INTO @generated_keys
VALUES('Malleable logarithmic casing');

SELECT t.[TurboEncabulatorID], t.[RowVersion]
FROM @generated_keys AS g 
   JOIN dbo.TurboEncabulators AS t 
   ON g.Id = t.TurboEncabulatorID 
WHERE @@ROWCOUNT > 0

Timetsampこれを取得するために句を使用することはできません。OUTPUT

これは、テーブルにトリガーがある場合、Timestamp出力が間違っているためです。

  • 初期挿入。タイムスタンプ: 1
  • OUTPUT 句はタイムスタンプを出力します: 1
  • トリガーは行を変更します。タイムスタンプ: 2

テーブルにトリガーがある場合、返されるタイムスタンプは決して正しくありません。したがって、別の を使用する必要SELECTがあります。

また、間違った行バージョンに苦しんでも構わないと思っていたとしても、セパレートを実行するもう 1 つの理由は、a をテーブル変数にSELECT出力できないことです。rowversion

DECLARE @generated_keys table([Id] uniqueidentifier, [Rowversion] timestamp)

INSERT INTO TurboEncabulators(StatorSlots)
OUTPUT inserted.TurboEncabulatorID, inserted.Rowversion INTO @generated_keys
VALUES('Malleable logarithmic casing');

これを行う 3 つ目の理由は、対称性のためです。UPDATEトリガーを使用してテーブルに対して を実行する場合、句は使用できません。OUTPUTでやろうUPDATEとするOUTPUTことはサポートされておらず、エラーが発生します:

それを行う唯一の方法は、フォローアップSELECTステートメントを使用することです。

UPDATE TurboEncabulators
SET StatorSlots = 'Lotus-O deltoid type'
WHERE ((TurboEncabulatorID = 1) AND (RowVersion = 792))

SELECT RowVersion
FROM TurboEncabulators
WHERE @@ROWCOUNT > 0 AND TurboEncabulatorID = 1
于 2016-11-04T15:05:48.960 に答える
17

@@IDENTITYは、現在の SQL 接続を使用して挿入された最後の ID です。これは、挿入ストアド プロシージャから返すのに適した値です。この場合、新しいレコードに ID を挿入するだけでよく、後で行が追加されたかどうかは気にしません。

SCOPE_IDENTITYは、現在の SQL 接続を使用して挿入された最後の ID であり、現在のスコープ内にあります。つまり、挿入後にトリガーに基づいて挿入された 2 番目の IDENTITY があった場合、SCOPE_IDENTITY には反映されず、実行した挿入のみが反映されます。 . 率直に言って、私はこれを使用する理由がありませんでした。

IDENT_CURRENT(tablename)は、接続またはスコープに関係なく挿入された最後の ID です。レコードを挿入していないテーブルの現在の IDENTITY 値を取得する場合は、これを使用できます。

于 2008-09-03T21:42:55.693 に答える
12

常にscope_identity()を使用してください。他に何も必要ありません。

于 2009-10-09T20:35:00.793 に答える