IDENTITY挿入された行を取得する最良の方法は何ですか?
私が知っている@@IDENTITYとIDENT_CURRENTとSCOPE_IDENTITYが、それぞれに付属の長所と短所を理解していません。
誰かが違いを説明してくれませんか、それぞれをいつ使うべきですか?
OUTPUTSQL Server の句よりも古いものです。
                IDENTITY挿入された行を取得する最良の方法は何ですか?
私が知っている@@IDENTITYとIDENT_CURRENTとSCOPE_IDENTITYが、それぞれに付属の長所と短所を理解していません。
誰かが違いを説明してくれませんか、それぞれをいつ使うべきですか?
OUTPUTSQL Server の句よりも古いものです。
                回答:
@@IDENTITY現在のセッションの任意のテーブルについて、すべてのスコープにわたって生成された最後のID値を返します。  スコープを超えているため、ここで注意する必要があります。現在のステートメントではなく、トリガーから値を取得できます。
SCOPE_IDENTITY()現在のセッションおよび現在のスコープ内の任意のテーブルに対して生成された最後のID値を返します。  一般的に何を使いたいか。
IDENT_CURRENT('tableName')任意のセッションおよびスコープの特定のテーブルに対して生成された最後のID値を返します。これにより、上記の2つが必要なものではない場合(非常にまれ)に、値を取得するテーブルを指定できます。また、@ Guy Starbuckが述べたように、「レコードを挿入していないテーブルの現在のIDENTITY値を取得する場合に使用できます。」
ステートメントのOUTPUT句を使用すると、そのINSERTステートメントを介して挿入されたすべての行にアクセスできます。特定のステートメントにスコープが設定されているため、上記の他の関数よりも簡単です。ただし、これはもう少し冗長で(テーブル変数/一時テーブルに挿入してからクエリする必要があります)、ステートメントがロールバックされるエラーシナリオでも結果が得られます。つまり、クエリが並列実行プランを使用している場合、これがIDを取得するための唯一の保証された方法です(並列処理をオフにする以外)。ただし、トリガーの前に実行され、トリガーによって生成された値を返すために使用することはできません。
output、あなたは結果を格納する一時テーブルを作成し、クエリを実行する必要はありません。ただ、オフのままinto出力句の一部を、それが結果セットに出力するでしょう。
                    OUTPUTので、限り、あなたはトリガを使用していないとエラーを処理しているとして、「最高」ですが、SCOPE_IDENTITY最も簡単であり、非常に稀に問題がある
                    挿入された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;
GOOUTPUTがあり、SQL Server 2000以前のバージョンのように見えないようです
                    私は他の人たちと同じことを言っているので、誰もが正しいので、私はそれをより明確にしようとしています。
@@IDENTITYクライアントのデータベースへの接続によって挿入された最後のもののIDを返します。
ほとんどの場合、これは問題なく機能しますが、トリガーが実行され、わからない新しい行が挿入され、必要な行ではなく、この新しい行からIDが取得される場合があります。
SCOPE_IDENTITY()この問題を解決します。データベースに送信したSQLコードに最後に挿入したもののIDを返します。トリガーが実行されて余分な行が作成されても、誤った値が返されることはありません。やったー
IDENT_CURRENT誰かが挿入した最後のIDを返します。他のアプリが偶然に別の行を挿入した場合、その行のIDではなく、その行のIDを取得します。
安全にプレイしたい場合は、常にを使用してくださいSCOPE_IDENTITY()。あなたがこだわり、@@IDENTITY後で誰かがトリガーを追加することを決めた場合、すべてのコードが壊れます。
新しく挿入された行の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)scope_identity()とにかく単一行の挿入(の最も一般的なケース)が並列プランを取得することは非常にまれです。そして、このバグはこの回答の1年以上前に修正されました。
                    output代わりに使用するすべてのSQLを書き換えることでしたscope_identity()。回答のクラスタリングに関するFUDを削除しました。
                    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場合、OUTPUTが間違っているためです。
テーブルにトリガーがある場合、返されるタイムスタンプは正しくありません。したがって、別のを使用する必要がありますSELECT。
また、不適切な行バージョンに苦しんでも構わないとしても、別の行を実行するもう1つの理由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 = 1TurboEncabulators:)
                    @@ IDENTITY、SCOPE_IDENTITY、IDENT_CURRENTは、テーブルのIDENTITY列に挿入された最後の値を返すという点で同様の関数です。
@@ IDENTITYおよびSCOPE_IDENTITYは、現在のセッションの任意のテーブルで生成された最後のID値を返します。ただし、SCOPE_IDENTITYは現在のスコープ内でのみ値を返します。@@ IDENTITYは特定のスコープに限定されません。
IDENT_CURRENTはスコープとセッションによって制限されません。指定されたテーブルに限定されます。IDENT_CURRENTは、任意のセッションおよびスコープの特定のテーブルに対して生成されたID値を返します。詳細については、IDENT_CURRENTを参照してください。
@@ IDENTITYは、現在のSQL接続を使用して挿入された最後のIDです。これは、新しいレコードに挿入されたIDが必要なだけの挿入ストアドプロシージャから戻るのに適した値であり、後でさらに行が追加されたかどうかは気にしません。
SCOPE_IDENTITYは、現在のSQL接続を使用して、現在のスコープに挿入された最後のIDです。つまり、挿入後にトリガーに基づいて2番目のIDENTITYが挿入された場合、SCOPE_IDENTITYには反映されず、実行した挿入のみが反映されます。 。正直なところ、私はこれを使用する理由がありませんでした。
IDENT_CURRENT(テーブル名)は、接続またはスコープに関係なく、最後に挿入されたIDです。これは、レコードを挿入していないテーブルの現在のIDENTITY値を取得する場合に使用できます。
SQL Serverの他のバージョンと話すことはできませんが、2012年には、直接出力することで問題なく動作します。一時テーブルを気にする必要はありません。
INSERT INTO MyTable
OUTPUT INSERTED.ID
VALUES (...)ちなみに、この手法は複数の行を挿入するときにも機能します。
INSERT INTO MyTable
OUTPUT INSERTED.ID
VALUES
    (...),
    (...),
    (...)出力
ID
2
3
4OUTPUT。一時テーブルが必要ない場合、クエリははるかに単純になります。
                    常に使用SCOPE_IDENTITY()は、他の何かの必要があることはありません。
を作成し、uuidそれを列に挿入します。次に、uuidを使用して行を簡単に識別できます。これが、実装できる唯一の100%機能するソリューションです。他のすべてのソリューションは複雑すぎるか、同じエッジケースで機能しません。例えば:
1)行を作成する
INSERT INTO table (uuid, name, street, zip) 
        VALUES ('2f802845-447b-4caa-8783-2086a0a8d437', 'Peter', 'Mainstreet 7', '88888');2)作成された行を取得する
SELECT * FROM table WHERE uuid='2f802845-447b-4caa-8783-2086a0a8d437';uuidデータベースにのインデックスを作成することを忘れないでください。したがって、行はより速く検出されます。
                    https://www.npmjs.com/package/uuid。  const uuidv4 = require('uuid/v4'); const uuid = uuidv4()
                    挿入する行のIDを保証するもう1つの方法は、ID値を指定し、SET IDENTITY_INSERT ON次にを使用することOFFです。これにより、IDの値が正確にわかるようになります。値が使用されていない限り、これらの値をID列に挿入できます。
CREATE TABLE #foo 
  ( 
     fooid   INT IDENTITY NOT NULL, 
     fooname VARCHAR(20) 
  ) 
SELECT @@Identity            AS [@@Identity], 
       Scope_identity()      AS [SCOPE_IDENTITY()], 
       Ident_current('#Foo') AS [IDENT_CURRENT] 
SET IDENTITY_INSERT #foo ON 
INSERT INTO #foo 
            (fooid, 
             fooname) 
VALUES      (1, 
             'one'), 
            (2, 
             'Two') 
SET IDENTITY_INSERT #foo OFF 
SELECT @@Identity            AS [@@Identity], 
       Scope_identity()      AS [SCOPE_IDENTITY()], 
       Ident_current('#Foo') AS [IDENT_CURRENT] 
INSERT INTO #foo 
            (fooname) 
VALUES      ('Three') 
SELECT @@Identity            AS [@@Identity], 
       Scope_identity()      AS [SCOPE_IDENTITY()], 
       Ident_current('#Foo') AS [IDENT_CURRENT] 
-- YOU CAN INSERT  
SET IDENTITY_INSERT #foo ON 
INSERT INTO #foo 
            (fooid, 
             fooname) 
VALUES      (10, 
             'Ten'), 
            (11, 
             'Eleven') 
SET IDENTITY_INSERT #foo OFF 
SELECT @@Identity            AS [@@Identity], 
       Scope_identity()      AS [SCOPE_IDENTITY()], 
       Ident_current('#Foo') AS [IDENT_CURRENT] 
SELECT * 
FROM   #foo これは、別のソースからデータをロードしたり、2つのデータベースからデータをマージしたりする場合などに、非常に役立つテクニックです。
これは古いスレッドですが、サーバーを再起動した後のID値のギャップのような、古いバージョンのSQL ServerのIDENTITY列のいくつかの落とし穴を回避する新しい方法があります。シーケンスはSQL Server 2016以降で使用できます。これは、TSQLを使用してSEQUENCEオブジェクトを作成する新しい方法です。これにより、SQL Serverで独自の数値シーケンスオブジェクトを作成し、その増分方法を制御できます。
次に例を示します。
CREATE SEQUENCE CountBy1  
    START WITH 1  
    INCREMENT BY 1 ;  
GO  次に、TSQLで次のシーケンスIDを取得するには、次のようにします。
SELECT NEXT VALUE FOR CountBy1 AS SequenceID
GOCREATE SEQUENCEおよびNEXT VALUE FORへのリンクは次のとおりです
Insertステートメントの後に、これを追加する必要があります。そして、データが挿入されているテーブル名について確認してください。挿入ステートメントによって現在影響を受けている行はありません。
IDENT_CURRENT('tableName')
INSERT INTO Table1(fields...) OUTPUT INSERTED.id VALUES (...)、または古いメソッド:INSERT INTO Table1(fields...) VALUES (...); SELECT SCOPE_IDENTITY();ExecuteScalar()を使用してc#で取得できます。