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


9

私が代わりにトリガを使用してテーブルに挿入、@@IdentityIDENT_CURRENT('Table')およびSCOPE_IDENTITY()リターンヌル。挿入された行の最後のIDを取得するにはどうすればよいですか?


トリガーがトリガーinsertedされたときに挿入される行はありませんINSTEAD OF
ypercubeᵀᴹ

このSOの質問を確認してください。stackoverflow.com/q/908257/27535
gbn

Select Id、.. Insertedから選択する必要があります。ここでは、Scope_Identity、@@ Identityは機能しません

回答:


8

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

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


挿入した行のデータ整合性を制御したい。保存する前に。データが良くない場合、エラー比例メッセージを出します。
mehdi lotfi

2
外部キーについて説明しています。トリガーではなく、子テーブルに挿入するのはアプリケーションの責任です。トリガーからそれを行うのは悪い設計です。とにかく、通常のAFTERトリガーから行うことができます。afterトリガーはエラーを発生させ、ロールバックを引き起こす可能性があります。これは、代わりのトリガーよりも優れたオプションです。
Remus Rusanu

1
「トリガーの代わりに深刻なコードのにおいがする」というなんてばかげた概念ですか?これらは、後トリガーと比較して非常に便利です。ビジネスルールに違反した場合、作業が2回行われ、行を挿入してからロールバックします。代わりにトリガーを使用すると、ビジネスルールを通常のDRIまたはその他の制約で実施できない場合に、作業が発生するのを防ぐことができます。
アーロンバートランド

1
「トリガーではなく深刻なコード臭い」は厳密な規則ではありませんが、完全なシステムで発生する可能性のある実際の問題に基づいています。一般に、ビジネスルールブレーカーがシステムで発生することはありません。データベースレベルに到達することは言うまでもありません。その場合、トリガーでのルール検証は、システムに穴がある場合の最後の防御メカニズムとしてのみ適切です。
Alireza

4
宣言の整合性は、常にトリガーよりも優れています。後トリガーは、代わりにトリガーよりも常に優れています。代わりにトリガーは、多くの状況で「ファンキー」な動作をします。DMLのパス最適化にアクセスすることは不透明であり、分離レベルの動作が不安定になります。代わりにトリガーは「代わりにアクセスストアドプロシージャである必要があった」と叫びます。そして、私は「仕事を2度行う」という議論をまったく購入しません。例外パスを最適化することは、特に頻繁にパスを遅くするという犠牲を払って、デザインに影響を与えるべきではありません。
Remus Rusanu

12

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

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(),(),()つまり、or を使用した複数行挿入INSERT...SELECT- SCOPE_IDENTITY変数に設定するのはどれですか。


挿入したレコードの結果を変数テーブルに保存して後で使用する方法。
mehdi lotfi

@mehdiは「後で」定義できますか?また、上記で宣言したtable変数に列を追加することはできませんか?
アーロンバートランド

3
私はあなたのテーブル名が大好きです。
Dan Esparza 2014

-1

主な問題:トリガーとエンティティフレームワークの両方が異なるスコープで動作します。問題は、トリガーで新しいPK値を生成すると、スコープが異なることです。したがって、このコマンドはゼロ行を返し、EFは例外をスローします。

解決策は、トリガーの最後に次のSELECTステートメントを追加することです。

SELECT * FROM deleted UNION ALL
SELECT * FROM inserted;

*の代わりに、すべての列名を指定できます

SELECT IDENT_CURRENT(‘tablename’) AS <IdentityColumnname>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.