Cara mendapatkan baris identitas terakhir Disisipkan saat menggunakan alih-alih pemicu

9

Ketika saya memasukkan ke dalam tabel menggunakan bukan pemicu @@Identity,, IDENT_CURRENT('Table')dan SCOPE_IDENTITY()mengembalikan nol. Bagaimana saya bisa mendapatkan identitas terakhir dari baris yang dimasukkan?

mehdi lotfi
sumber
Ada insertedtetapi tidak ada baris yang dimasukkan saat INSTEAD OFpemicu.
ypercubeᵀᴹ
Periksa pertanyaan SO ini: mungkin membantu. stackoverflow.com/q/908257/27535
gbn
Anda harus memilih Select Id, .. dari Inserted, di sini Scope_Identity, @@ Identity tidak akan berfungsi

Jawaban:

8

Dengan pemicu INSTEAD_OF itu berarti belum ada sisipan yang terjadi. Anda tidak dapat mengetahui identitasnya karena belum dibuat. Mengintipkan nilai dari metadata dimungkinkan ( DBCC CHECKIDENT) tetapi mengandalkannya tidak akan berfungsi dengan benar di bawah konkurensi dan di samping itu membutuhkan hak yang lebih tinggi.

INSTEAD_OF pemicu sangat jarang diperlukan dan bau kode yang serius. Anda yakin membutuhkannya? Tidak bisakah Anda melakukan pekerjaan dengan pemicu SETELAH reguler?

Remus Rusanu
sumber
Saya ingin mengontrol integritas data dari baris yang dimasukkan. sebelum menyimpannya. Jika data tidak bagus, saya menaikkan pesan proporsional kesalahan.
mehdi lotfi
2
Anda menggambarkan kunci asing. Seharusnya tanggung jawab aplikasi untuk memasukkan dalam tabel anak, bukan pemicu. Melakukannya dari pemicu adalah desain yang buruk, dan bagaimanapun hal itu dapat dilakukan dari pemicu SETELAH yang normal. Pemicu setelah dapat meningkatkan kesalahan dan menyebabkan rollback, yang merupakan opsi yang lebih baik daripada pemicu.
Remus Rusanu
1
Apa gagasan yang absurd - "bukannya pemicu adalah bau kode serius"? Mereka sangat berguna dibandingkan dengan pemicu setelah - di mana, jika aturan bisnis Anda dilanggar, Anda telah melakukan pekerjaan dua kali - Anda telah memasukkan baris dan kemudian Anda mengembalikannya. Alih-alih pemicu dapat mencegah pekerjaan apa pun terjadi jika aturan bisnis Anda tidak dapat ditegakkan dengan DRI normal atau kendala lainnya.
Aaron Bertrand
1
Sementara "bukannya pemicu adalah bau kode serius", bukan aturan yang ketat, itu didasarkan pada masalah aktual yang mungkin disebabkan oleh sistem yang lengkap. Secara umum, pelanggar aturan bisnis tidak boleh terjadi dalam sistem, apalagi mencapai tingkat basis data. Dalam hal itu, validasi aturan dalam pelatuk hanya sesuai sebagai mekanisme pertahanan terakhir jika ada lubang di sistem.
Alireza
4
Integritas deklaratif selalu lebih baik daripada pemicu. Pemicu setelah selalu lebih baik daripada pemicu. Alih-alih pemicu memiliki perilaku 'funky' dalam banyak situasi, mereka tidak jelas untuk mengakses optimisasi jalur di DML, mereka membuat tingkat isolasi berperilaku tidak menentu. Alih-alih pemicu berteriak, "Seharusnya aku yang mengakses prosedur yang tersimpan '. Dan saya tidak membeli argumen 'lakukan pekerjaan dua kali' sama sekali, mengoptimalkan jalur pengecualian seharusnya tidak mempengaruhi desain, khususnya dengan mengorbankan jalan yang sering melambat .
Remus Rusanu
12

Di alih-alih pemicu, Anda pasti bisa mendapatkan nilai yang dimasukkan ... tetapi tidak sampai setelah Anda melakukan memasukkan.

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

Hasil:

id
----
1

Sekarang bersihkan:

DROP TABLE dbo.SmellThis;

Sebagai tambahan, Anda seharusnya tidak pernah, pernah menggunakan @@IDENTITYatau IDENT_CURRENT()tetap. Dan SCOPE_IDENTITYharus disediakan untuk situasi di mana Anda tahu hanya satu baris yang bisa dimasukkan. Kesalahpahaman umum dengan pemicu adalah bahwa mereka menjalankan per baris, seperti pada platform lain, tetapi dalam SQL Server mereka menjalankan per operasi - jadi masukkan multi-baris menggunakan VALUES(),(),()atau INSERT...SELECT- yang SCOPE_IDENTITYakan Anda atur ke variabel Anda?

Aaron Bertrand
sumber
Bagaimana saya menyimpan hasil rekaman yang dimasukkan dalam tabel variabel untuk digunakan nanti.
mehdi lotfi
@mehdi dapatkah Anda mendefinisikan "nanti"? Dan tidak bisakah Anda menambahkan kolom ke variabel tabel yang sudah saya nyatakan di atas?
Aaron Bertrand
3
Saya suka nama meja Anda.
Dan Esparza
-1

Masalah Utama: Kerangka kerja Pemicu dan Entitas bekerja dalam lingkup yang berbeda. Masalahnya adalah, bahwa jika Anda menghasilkan nilai PK baru di pemicu, itu adalah ruang lingkup yang berbeda. Dengan demikian perintah ini mengembalikan nol baris dan EF akan melempar pengecualian.

Solusinya adalah dengan menambahkan pernyataan SELECT berikut di akhir Pemicu Anda:

SELECT * FROM deleted UNION ALL
SELECT * FROM inserted;

di tempat * Anda dapat menyebutkan semua nama kolom termasuk

SELECT IDENT_CURRENT(‘tablename’) AS <IdentityColumnname>
Ashish Mishra
sumber