IDENTITY
挿入された行を取得する最良の方法は何ですか?
@@IDENTITY
and IDENT_CURRENT
andについては知ってSCOPE_IDENTITY
いますが、それぞれに付随する長所と短所がわかりません。
誰かが違いと、それぞれをいつ使用すべきかを説明してもらえますか?
IDENTITY
挿入された行を取得する最良の方法は何ですか?
@@IDENTITY
and IDENT_CURRENT
andについては知ってSCOPE_IDENTITY
いますが、それぞれに付随する長所と短所がわかりません。
誰かが違いと、それぞれをいつ使用すべきかを説明してもらえますか?
@@IDENTITY
すべてのスコープにわたって、現在のセッションの任意のテーブルに対して生成された最後の ID 値を返します。 スコープをまたいでいるので、ここは注意が必要です。現在のステートメントではなく、トリガーから値を取得できます。
SCOPE_IDENTITY()
現在のセッションと現在のスコープで任意のテーブルに対して生成された最後の ID 値を返します。 一般的に使用したいもの。
IDENT_CURRENT('tableName')
任意のセッションおよび任意のスコープで特定のテーブルに対して生成された最後の ID 値を返します。これにより、上記の2つが必要なものではない場合に備えて、値を取得するテーブルを指定できます(非常にまれです)。また、@ Guy Starbuckが述べたように、「レコードを挿入していないテーブルの現在の IDENTITY 値を取得する場合は、これを使用できます。」
ステートメントのOUTPUT
句により、そのINSERT
ステートメントを介して挿入されたすべての行にアクセスできます。特定のステートメントにスコープが設定されているため、上記の他の関数よりも簡単です。ただし、これはもう少し冗長で (テーブル変数/一時テーブルに挿入してからクエリを実行する必要があります)、ステートメントがロールバックされるエラー シナリオでも結果が得られます。つまり、クエリで並列実行プランが使用されている場合、これがID を取得するための保証された唯一の方法です (並列処理をオフにする以外は)。ただし、トリガーの前に実行されるため、トリガーによって生成された値を返すために使用することはできません。
挿入された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
私は他の人たちと同じことを言っているので、誰もが正しいです.私はそれをより明確にしようとしています.
@@IDENTITY
クライアントのデータベースへの接続によって最後に挿入されたものの ID を返します。
ほとんどの場合、これで問題なく動作しますが、トリガーによって、知らない新しい行が挿入され、目的の行ではなく、この新しい行から ID が取得されることがあります。
SCOPE_IDENTITY()
この問題を解決します。データベースに送信した SQL コードに最後に挿入したものの ID を返します。トリガーが実行されて余分な行が作成されても、間違った値が返されることはありません。万歳
IDENT_CURRENT
誰かによって挿入された最後の 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)
MSDN から
@@IDENTITY、SCOPE_IDENTITY、および IDENT_CURRENT は、テーブルの IDENTITY 列に挿入された最後の値を返すという点で類似した関数です。
@@IDENTITY と SCOPE_IDENTITY は、現在のセッションの任意のテーブルで生成された最後の ID 値を返します。ただし、SCOPE_IDENTITY は現在のスコープ内でのみ値を返します。@@IDENTITY は特定のスコープに限定されません。
IDENT_CURRENT はスコープとセッションによって制限されません。指定されたテーブルに限定されます。IDENT_CURRENT は、任意のセッションおよび任意のスコープで特定のテーブルに対して生成された ID 値を返します。詳細については、IDENT_CURRENT を参照してください。
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
出力が間違っているためです。
テーブルにトリガーがある場合、返されるタイムスタンプは決して正しくありません。したがって、別の を使用する必要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
@@IDENTITYは、現在の SQL 接続を使用して挿入された最後の ID です。これは、挿入ストアド プロシージャから返すのに適した値です。この場合、新しいレコードに ID を挿入するだけでよく、後で行が追加されたかどうかは気にしません。
SCOPE_IDENTITYは、現在の SQL 接続を使用して挿入された最後の ID であり、現在のスコープ内にあります。つまり、挿入後にトリガーに基づいて挿入された 2 番目の IDENTITY があった場合、SCOPE_IDENTITY には反映されず、実行した挿入のみが反映されます。 . 率直に言って、私はこれを使用する理由がありませんでした。
IDENT_CURRENT(tablename)は、接続またはスコープに関係なく挿入された最後の ID です。レコードを挿入していないテーブルの現在の IDENTITY 値を取得する場合は、これを使用できます。
常にscope_identity()を使用してください。他に何も必要ありません。