web-dev-qa-db-ja.com

トリガーの代わりに使用するときに挿入された最後のID行を取得する方法

トリガーの代わりにを使用してテーブルに挿入すると、_@@Identity_、IDENT_CURRENT('Table')およびSCOPE_IDENTITY()はnullを返します。挿入された行の最後のIDを取得するにはどうすればよいですか?

8
mehdi lotfi

INSTEAD_OFトリガーの場合、挿入はまだ発生していません。 IDはまだ生成されていないため、識別できません。メタデータからの値のスニークは可能です( DBCC CHECKIDENT )ですが、これに依存することは、同時実行では正しく機能しません。また、昇格された特権が必要です。

INSTEAD_OFトリガーはほとんど必要なく、深刻なコードの臭いがします。本当に必要ですか?通常のAFTERトリガーで作業できませんか?

8
Remus Rusanu

トリガーの代わりに、挿入された値を確実に取得できます...しかし、挿入を実行するまでは取得できません。

_USE tempdb;
GO

CREATE TABLE dbo.SmellThis
(
  id INT IDENTITY(1,1),
  name VARCHAR(32)
);
GO

CREATE TRIGGER dbo.SmellThis_First
ON dbo.SmellThis
INSTEAD OF INSERT
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @ids TABLE(id INT);

    IF NOT EXISTS 
    (
      SELECT 1 FROM sys.objects AS o
        INNER JOIN inserted AS i
        ON o.name = i.name
    )
    INSERT dbo.SmellThis(name)  
      OUTPUT inserted.id INTO @ids
      SELECT name 
      FROM inserted;

    SELECT id FROM @ids;
END
GO

INSERT dbo.SmellThis(name) SELECT 'Remus';
GO
_

結果:

_id
----
1
_

次にクリーンアップします。

_DROP TABLE dbo.SmellThis;
_

余談ですが、決して_@@IDENTITY_またはIDENT_CURRENT()を決して使用しないでください。また、_SCOPE_IDENTITY_は、挿入できる行が1つだけであることがわかっている場合のために予約する必要があります。トリガーに関する一般的な誤解は、他のプラットフォームと同様に、トリガーが行ごとに発生することですが、SQL Serverでは操作ごとに発生するため、VALUES(),(),()または_INSERT...SELECT_を使用した複数行の挿入-_SCOPE_IDENTITY_変数に設定しますか?

11
Aaron Bertrand