Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Pemicu SQL Server:Pemicu DML

Di SQL Server, pemicu adalah objek database yang dieksekusi setiap kali peristiwa pemicu terjadi di database atau server.

Pemicu memainkan peran kunci dalam mencapai persyaratan Bisnis seperti memperingatkan orang yang ditargetkan, memulai pekerjaan, atau operasi lainnya. Karena Pemicu dapat menangani banyak operasi semacam itu, kita harus mendefinisikannya dengan hati-hati untuk menghindari dampak kinerja.

Pada artikel ini, kita akan membahas Pemicu, jenis Pemicu, dan berbagai pilihan Pemicu yang tersedia. Selain itu, kami akan mempelajari tindakan pencegahan yang diperlukan saat menggunakan pemicu DML.

Pemicu dalam SQL

Pemicu adalah jenis khusus prosedur Tersimpan yang dieksekusi pada peristiwa yang ditentukan, menjalankan skrip yang ditentukan dalam tubuh Pemicu. Ada beberapa jenis pemicu:

  • Pemicu DML – untuk melakukan operasi DML seperti perintah INSERT, UPDATE, dan DELETE pada tabel.
  • Pemicu DDL – untuk melakukan operasi DDL seperti perintah CREATE, ALTER, dan DROP di semua objek di Database atau Server.
  • Pemicu Masuk – untuk upaya masuk ke instance SQL Server selama acara LOGON.

Pemicu DML di SQL Server

Pemicu DML adalah pemicu yang dipicu oleh perintah DML (INSERT, UPDATE, atau DELETE) pada tabel atau tampilan. Kami dapat membuat Pemicu tersebut pada tabel atau tampilan tersebut hanya di tempat data berada sehingga mereka menerima perintah DML pada tabel atau tampilan tersebut.

Berdasarkan waktu pengaktifan/pemanggilan, pemicu DML dapat berupa jenis berikut:

  • UNTUK atau SETELAH Jenis Pemicu – pemicu dipanggil setelah berhasil menyelesaikan pernyataan DML pada tabel atau tampilan. Catatan:pemicu AFTER dapat dibuat hanya pada Tabel, bukan Tampilan.
  • BUKAN Jenis Pemicu – Pemicu akan dipanggil sebelum (BUKAN) skrip DML yang dieksekusi pada Tabel atau tampilan.

SQL Server membuat dua tabel khusus atau logis bernama INSERTED dan DIPERBARUI setiap kali pemicu DML dibuat di seluruh Tabel atau tampilan. Tabel logis ini membantu mengidentifikasi perubahan catatan yang terjadi melalui operasi INSERT/UPDATE/DELETE. Dengan cara ini, ini memastikan bahwa pemicu DML berfungsi secara efektif.

  • DIMASUKKAN tabel logis menyimpan salinan catatan baru dari catatan yang dimodifikasi selama operasi INSERT dan UPDATE. Ketika record baru ditambahkan ke tabel aktual, record tersebut juga ditambahkan ke tabel INSERTED. Demikian pula, setiap perubahan pada rekaman yang ada melalui pernyataan UPDATE memindahkan nilai terbaru ke tabel INSERTED dan nilai yang lebih lama – ke tabel logika DELETED.
  • DIHAPUS tabel logis menyimpan salinan nilai yang lebih lama selama operasi UPDATE dan DELETE. Setiap kali catatan diperbarui, nilai yang lebih lama disalin ke tabel DELETED. Setiap kali record dihapus dari tabel yang sebenarnya, record dimasukkan ke tabel DELETED.

SQL Server memiliki fungsi bawaan COLUMN_UPDATED() dan PERBARUI() untuk mengidentifikasi keberadaan operasi INSERT atau UPDATE pada kolom tertentu.

  • COLUMN_UPDATED() mengembalikan nilai varbinary kolom yang dipengaruhi oleh operasi INSERT atau UPDATE.
  • PERBARUI() menerima nama kolom sebagai parameter input dan mengembalikan informasi apakah kolom tersebut memiliki perubahan data sebagai bagian dari operasi INSERT atau UPDATE.

BUKAN UNTUK REPLIKASI properti dapat digunakan dalam pemicu DML agar tidak memicunya untuk perubahan yang datang melalui proses Replikasi.

Pemicu DML juga dapat dibuat dengan .Net Framework Common Language Runtime (CLR).

Sistem DMV sys.triggers menyimpan daftar semua pemicu cakupan basis data. Kita dapat menggunakan kueri di bawah ini untuk mengambil detail semua pemicu DML dalam Database:

SELECT * 
FROM sys.triggers
WHERE type = 'TR';

Definisi Pemicu DML dapat dilihat jika pemicu tidak dienkripsi. Kami menggunakan salah satu opsi di bawah ini:

sys.sql_modules

SELECT OBJECT_SCHEMA_NAME(object_id, db_id()) Schema_name, OBJECT_NAME(object_id) Trigger_Name, definition
FROM sys.sql_modules  
WHERE object_id = OBJECT_ID(<trigger_name>);   

OBJECT_DEFINITION() fungsi

SELECT OBJECT_DEFINITION (OBJECT_ID(<trigger_name>)) AS ObjectDefinition; 

sp_helptext prosedur tersimpan

EXEC sp_helptext '<trigger_name>';

Semua Kemungkinan Acara DML tersedia di sys.events meja. Kita dapat melihatnya menggunakan kueri di bawah ini:

SELECT * 
FROM sys.events;

Sintaks Pemicu DML

CREATE TRIGGER <trigger_name>
ON <schema_name.table_name | schema_name.view_name > 
[ WITH <DML_trigger_option> [ ,...n ] ]  
{ FOR | AFTER | INSTEAD OF} <event_type>
AS { sql_statement | EXTERNAL NAME <method specifier> }  

Untuk tujuan demo, saya telah membuat dua tabel bernama Penjualan dan Riwayat Penjualan dengan beberapa kolom dalam database pengujian:

CREATE TABLE Sales (SalesId int IDENTITY NOT NULL, SalesDate datetime, Itemcount int, price money);
CREATE TABLE SalesHistory (SalesId int NOT NULL, SalesDate datetime, Itemcount int, price money, ChangeType varchar(10), ChangeDate datetime DEFAULT GETDATE(), ChangedUser varchar(100) DEFAULT SUSER_NAME());
GO

Seperti yang Anda lihat, SalesHistory tabel memiliki 3 kolom tambahan untuk melacak tanggal modifikasi dan nama pengguna yang meminta perubahan. Jika diperlukan, kami dapat memiliki satu lagi kolom Identitas didefinisikan dan menjadikannya sebagai kunci Utama juga.

MASUKKAN Pemicu

Kami membuat pemicu INSERT sederhana di Penjualan tabel untuk INSERT setiap perubahan catatan baru ke SalesHistory meja. Gunakan skrip di bawah ini:

CREATE TRIGGER TR_INS_Sales ON Sales
FOR INSERT 
AS
BEGIN
  INSERT INTO SalesHistory(SalesId,SalesDate,Itemcount,price,ChangeType)
  SELECT SalesId
    	,SalesDate
	,Itemcount
	,price
	,'INSERT'
  FROM inserted
END
GO

Untuk menjelaskan sintaks pemicu, kami telah membuat pemicu DML bernama TR_INS_Sales di Penjualan meja. Itu harus memicu pemicu hanya untuk operasi INSERT – memasukkan catatan ke SalesHistory tabel dari tabel yang disisipkan.

Seperti yang kita ketahui, disisipkan adalah tabel logis yang menangkap perubahan yang terjadi di tabel Sumber (Penjualan tabel dalam kasus kami).

Kita dapat melihat tabel logika khusus lainnya dihapus di pemicu UPDATE karena dihapus tabel tidak berlaku untuk pemicu INSERT.

Mari tambahkan catatan baru untuk memeriksa apakah catatan dimasukkan ke SalesHistory tabel secara otomatis.

INSERT INTO Sales(SalesDate,Itemcount,price)
VALUES ('2021-01-01', 5, 100);

Meskipun kami hanya memasukkan satu catatan ke dalam Penjualan tabel, kami mendapatkan 2 baris dari 1 baris terpengaruh pesan. Catatan kedua muncul karena operasi INSERT sebagai bagian dari pemicu yang dipanggil oleh aktivitas INSERT di Penjualan tabel – menyisipkan catatan ke SalesHistory tabel.

Mari kita verifikasi catatan di kedua Penjualan dan Riwayat Penjualan tabel:

SELECT * 
FROM Sales

SELECT * 
FROM SalesHistory

Kita dapat melihat bahwa Tanggal Perubahan dan Pengguna yang Diubah secara otomatis terisi. Itu karena kami merancang Sejarah our kami tabel dengan nilai default sebagai GETDATE() dan SUSER_NAME() .

Pengguna akhir dapat melihat melalui Pemicu atau cara lain INSERT mereka diaudit melalui 1 baris tambahan yang terpengaruh pesan. Jika Anda ingin memantau perubahan tanpa memberi tahu pengguna, Anda perlu menerapkan SET ROWCOUNT ON memerintah. Ini menekan hasil yang ditampilkan untuk operasi DML yang terjadi di dalam pemicu.

Mari MENGUBAH pemicu kita menggunakan skrip dengan SET ROWCOUNT ON opsi dan lihat aksinya:

ALTER TRIGGER TR_INS_Sales ON Sales
FOR INSERT 
AS
BEGIN
SET NOCOUNT ON
  INSERT INTO SalesHistory(SalesId,SalesDate,Itemcount,price,ChangeType)
  SELECT SalesId
    ,SalesDate
	,Itemcount
	,price
	,'INSERT'
  FROM inserted
END
GO

Sekarang, kami memasukkan catatan lain ke dalam Penjualan tabel:

INSERT INTO Sales(SalesDate,Itemcount,price)
VALUES ('2021-02-01', 1, 50);

Kami hanya dapat melihat satu 1 baris terpengaruh pesan. Dengan demikian, audiens target mungkin tidak diberi tahu bahwa tindakan mereka sedang dipantau sama sekali.

Mari kita verifikasi apakah pemicu INSERT dipanggil dengan memverifikasi Penjualan dan Riwayat Penjualan tabel.

Ya, acara INSERT di Penjualan tabel berhasil dipicu. Catatan dimasukkan ke dalam SalesHistory tabel tanpa memberi tahu pengguna.

Oleh karena itu, jika Anda membuat pemicu untuk tujuan audit, tombol SET NOCOUNT ON diperlukan. Ini memungkinkan untuk mengaudit tanpa memberi tahu siapa pun.

PERBARUI Pemicu

Sebelum membuat pemicu UPDATE aktual di Penjualan tabel, mari kita lihat kembali tabel logis yang dimasukkan dan dihapus. Buat contoh pemicu UPDATE di Penjualan tabel:

CREATE TRIGGER TR_UPD_Sales ON Sales
FOR UPDATE 
AS
BEGIN
SELECT * FROM inserted
SELECT * FROM deleted
END
GO

Pemicu UPDATE berhasil dibuat. Sekarang, mari kita INSERT record baru secara tidak benar. Nanti kami akan memperbaruinya untuk memverifikasi pemicu UPDATE yang sedang beraksi:

INSERT INTO Sales(SalesDate,Itemcount,price)
VALUES ('2021-02-01', 1, 50);

Kami memiliki catatan di bawah di seluruh Penjualan dan Riwayat Penjualan tabel:

Ayo perbarui SalesId =3 di Penjualan tabel dengan nilai baru. Kami akan melihat data di seluruh tabel yang dimasukkan dan dihapus:

UPDATE Sales
SET SalesDate = '2021-03-01'
	, Itemcount = 3
	, price = 500
WHERE SalesId = 3

Saat operasi UPDATE berlangsung, semua nilai baru atau yang dimodifikasi akan tersedia di tabel yang disisipkan, dan nilai lama akan tersedia di tabel yang dihapus:

Sekarang, mari ubah pemicu UPDATE dengan skrip di bawah ini dan verifikasi dalam tindakan:

ALTER TRIGGER TR_UPD_Sales ON Sales
FOR UPDATE 
AS
BEGIN
  INSERT INTO SalesHistory(SalesId,SalesDate,Itemcount,price,ChangeType)
  SELECT SalesId
    ,SalesDate
	,Itemcount
	,price
	,'UPDATE'
  FROM inserted
END
GO

Pemicu UPDATE berhasil diubah, dan kita dapat menjalankan skrip UPDATE yang sama lagi:

Sekarang, kita dapat melihat 1 baris terpengaruh pesan dua kali. Ini menunjukkan pelaksanaan operasi UPDATE pada Penjualan tabel dan operasi INSERT pada SalesHistory meja. Mari kita verifikasi ini dengan memilih di kedua tabel:

Aktivitas UPDATE dilacak di SalesHistory tabel sebagai rekor baru. Sebelum catatan itu, kami memiliki satu lagi yang ditampilkan saat catatan dimasukkan terlebih dahulu.

HAPUS Pemicu

Sampai sekarang, kami menguji UNTUK atau SETELAH jenis pemicu untuk operasi INSERT atau UPDATE. Sekarang, kita dapat mencoba menggunakan BUKAN jenis pemicu DML untuk operasi DELETE. Gunakan skrip di bawah ini:

CREATE TRIGGER TR_DEL_Sales ON Sales
INSTEAD OF DELETE 
AS
BEGIN
	RAISERROR ('Notify Sales Team', 16, 10);  
END
GO

Pemicu DELETE berhasil dibuat. Ini akan mengirim pesan kesalahan ke klien alih-alih melakukan perintah DELETE di Penjualan tabel.

Mari kita coba untuk menghapus catatan SalesID =3 dari Penjualan tabel menggunakan script di bawah ini:

DELETE FROM Sales
WHERE SalesId = 3

Kami telah mencegah pengguna menghapus catatan dari Penjualan meja. Pemicu memunculkan pesan kesalahan.

Mari kita juga memverifikasi apakah catatan telah dihapus dari Penjualan tabel dan jika ada perubahan pada SalesHistory tabel:

Karena kami telah mengeksekusi skrip pemicu sebelum pernyataan DELETE yang sebenarnya menggunakan INSTEAD OF trigger, operasi DELETE pada SalesId=3 tidak berhasil sama sekali. Oleh karena itu, tidak ada perubahan yang terlihat di kedua Penjualan dan Riwayat Penjualan tabel.

Mari kita ubah pemicu menggunakan skrip di bawah ini untuk mengidentifikasi upaya DELETE pada tabel:

ALTER TRIGGER TR_DEL_Sales ON Sales
INSTEAD OF DELETE 
AS
BEGIN
  INSERT INTO SalesHistory(SalesId,SalesDate,Itemcount,price,ChangeType)
  SELECT SalesId
    ,SalesDate
	,Itemcount
	,price
	,'DELETE ATP'
  FROM deleted 
END
GO

Pemicu berhasil dimodifikasi. Mari kita hapus SalesId =3 catatan dari Penjualan tabel lagi:

Eksekusi pernyataan DELETE menunjukkan 1 baris terpengaruh pesan dua kali. Mari kita periksa catatan di seluruh Penjualan dan Riwayat Penjualan tabel untuk melihat apa yang sebenarnya terjadi di sana:

Logika yang digunakan dalam Pemicu DELETE adalah untuk menangkap setiap upaya DELETE pada tabel tanpa benar-benar menghapus catatan dari Penjualan tabel menggunakan BUKAN pemicu. Kami dapat mengonfirmasi bahwa catatan tersebut tidak dihapus dari Penjualan tabel, dan catatan baru dimasukkan ke dalam SalesHistory tabel.

Satu Pemicu untuk Menangani Operasi INSERT, UPDATE, dan DELETE

Sampai sekarang, kami telah membuat 3 pemicu untuk menangani operasi INSERT, UPDATE, dan DELETE pada satu tabel. Jika kita memiliki banyak pemicu, akan sulit untuk mengelolanya, terutama jika tidak didokumentasikan dengan baik. Mungkin ada masalah kinerja jika pengembang menggunakan logika yang bertentangan di beberapa pemicu.

Saya pribadi merekomendasikan menggunakan satu pemicu dengan semua logika digabungkan untuk menghindari potensi kehilangan data atau masalah kinerja. Kami dapat mencoba menggabungkan 3 pemicu dalam satu pemicu untuk kinerja yang lebih baik. Namun sebelum kita melakukannya, mari kita periksa cara MENGHENTIKAN pemicu yang ada dan cara Menonaktifkan atau Mengaktifkan pemicu.

Lepaskan Pemicunya

Untuk menggabungkan 3 pemicu menjadi satu, pertama-tama kita harus MENGHAPUS 3 pemicu ini. Hal ini dimungkinkan melalui pendekatan SSMS dan T-SQL.

Di SSMS, perluas Uji basis data > Tabel > Penjualan tabel> Pemicu .

Kami dapat melihat 3 pemicu kami dibuat sejauh ini:

Untuk melepaskan pemicu, cukup klik kanan pada pemicu> Hapus > Oke .

Jika Anda lebih suka menggunakan T-SQL, lihat sintaks di bawah ini untuk menghapus pemicu:

DROP TRIGGER <trigger_name>

Ada TR_INS_Sales pemicu yang kami buat di Penjualan meja. Skripnya akan menjadi:

DROP TRIGGER TR_INS_Sales

Penting :Menjatuhkan tabel akan menghapus semua pemicu secara default.

Nonaktifkan dan Aktifkan Pemicu

Alih-alih menjatuhkan pemicu, kita dapat menonaktifkannya sementara dengan Nonaktifkan pemicu opsi melalui SSMS atau T-SQL.

Di SSMS, klik kanan pada Nama pemicu> Nonaktifkan . Setelah dinonaktifkan, pemicu tidak akan diaktifkan hingga Anda mengaktifkannya kembali.

Saat Pemicu bekerja, tombol Aktifkan opsi berwarna abu-abu. Saat Anda menonaktifkannya, tombol Aktifkan opsi akan menjadi terlihat dan aktif.

Jika Anda lebih suka menggunakan T-SQL, Anda dapat menonaktifkan dan mengaktifkan pemicu menggunakan skrip di bawah ini:

-- To Disable all triggers on a specific table
DISABLE TRIGGER ALL ON <table_name>;

-- To Disable a specific trigger on a table
DISABLE TRIGGER <trigger_name> ON <table_name>;

-- To Enable all triggers on a specific table
ENABLE TRIGGER ALL ON <table_name>;

-- To Enable a specific trigger on a table
ENABLE TRIGGER <trigger_name> ON <table_name>;

Untuk menonaktifkan dan mengaktifkan TR_INS_Sales khusus kami pemicu di Penjualan tabel, kami menggunakan skrip di bawah ini:

-- To Disable TR_INS_Sales trigger on Sales table
DISABLE TRIGGER TR_INS_Sales ON Sales;

-- To Enable TR_INS_Sales trigger on Sales table
ENABLE TRIGGER TR_INS_Sales ON Sales;

Dengan demikian, kita telah mempelajari cara DROP , NONAKTIFKAN , dan AKTIFKAN pemicu. Saya akan menghapus 3 pemicu yang ada dan membuat satu pemicu yang mencakup semua 3 operasi atau menyisipkan, memperbarui, dan menghapus menggunakan skrip di bawah ini:

DROP TRIGGER TR_INS_Sales
DROP TRIGGER TR_UPD_Sales
DROP TRIGGER TR_DEL_Sales
GO

CREATE TRIGGER TR_INS_UPD_DEL_Sales ON Sales
FOR INSERT, UPDATE, DELETE
AS
BEGIN
IF (SELECT COUNT (*) FROM deleted) = 0
BEGIN
  INSERT INTO SalesHistory(SalesId,SalesDate,Itemcount,price,ChangeType)
  SELECT SalesId
    ,SalesDate
	,Itemcount
	,price
	,'INSERT'
  FROM inserted
END
ELSE IF (SELECT COUNT (*) FROM inserted) = 0
BEGIN
  INSERT INTO SalesHistory(SalesId,SalesDate,Itemcount,price,ChangeType)
  SELECT SalesId
    ,SalesDate
	,Itemcount
	,price
	,'DELETE'
  FROM deleted
END
ELSE IF (UPDATE (SalesDate) OR UPDATE (ItemCount) OR UPDATE (Price))
BEGIN
  INSERT INTO SalesHistory(SalesId,SalesDate,Itemcount,price,ChangeType)
  SELECT SalesId
    ,SalesDate
	,Itemcount
	,price
	,'UPDATE'
  FROM inserted
END 
END
GO

Pembuatan pemicu tunggal berhasil. Kami telah menggunakan logika untuk mengidentifikasi operasi dengan menggunakan tabel yang dimasukkan dan dihapus.

Untuk operasi INSERT, tabel yang dihapus tidak akan diisi. Untuk operasi DELETE, tabel yang disisipkan tidak akan diisi. Kami dapat mengidentifikasi operasi ini dengan mudah. Jika 2 kondisi ini tidak cocok maka ini adalah operasi UPDATE, dan kita dapat menggunakan pernyataan ELSE sederhana.

Saya telah menggunakan UPDATE() berfungsi untuk menunjukkan cara kerjanya. Jika ada pembaruan pada kolom tersebut, tindakan pemicu UPDATE akan diaktifkan. Kami juga dapat menggunakan COLUMNS_UPDATED() fungsi yang telah kita bahas sebelumnya untuk mengidentifikasi operasi UPDATE juga.

Mari kita uji pemicu baru kita dengan memasukkan catatan baru:

INSERT INTO Sales(SalesDate,Itemcount,price)
VALUES ('2021-04-01', 4, 400);

Memverifikasi catatan di seluruh Penjualan dan Riwayat Penjualan tabel menunjukkan data seperti di bawah ini:

Ayo coba perbarui SalesId =2 catatan:

UPDATE Sales
SET price = 250
WHERE SalesId = 2;

Mari kita coba skrip DELETE melalui prosedur ini di SalesId =4 catatan:

DELETE FROM Sales
WHERE SalesId = 4;

Seperti yang dapat kita perhatikan, SalesId =4 telah dihapus dari Penjualan tabel karena ini adalah UNTUK atau SETELAH pemicu, membuat operasi DELETE berhasil di Penjualan tabel lalu masukkan catatan ke SalesHistory tabel.

Tujuan Pemicu DML

Pemicu DML berfungsi secara efektif untuk skenario berikut:

  1. Lacak perubahan historis operasi INSERT, UPDATE, dan DELETE pada tabel tertentu.
  2. Audit peristiwa DML yang terjadi di meja tanpa memaparkan aktivitas Audit kepada pengguna.
  3. Cegah terjadinya perubahan DML pada tabel melalui BUKAN memicu dan memperingatkan pengguna dengan pesan kesalahan tertentu.
  4. Kirim pemberitahuan ke orang yang ditargetkan saat mencapai kondisi yang telah ditentukan sebelumnya.
  5. Mulai Pekerjaan Agen Server SQL atau proses lainnya setiap kali mencapai kondisi yang telah ditentukan sebelumnya.

Dan, Anda dapat menggunakannya untuk persyaratan logika bisnis lainnya yang dapat Anda terapkan dengan pernyataan T-SQL.

Kesimpulan

Badan pemicu DML mirip dengan prosedur tersimpan. Kami dapat menerapkan logika Bisnis apa pun yang diperlukan, tetapi kami harus berhati-hati saat menulis logika tersebut untuk menghindari potensi masalah.

Meskipun SQL Server mendukung pembuatan beberapa pemicu pada satu tabel, lebih baik untuk menggabungkannya ke satu Pemicu. Dengan cara ini, Anda dapat mempertahankan pemicu dengan mudah dan memecahkan masalah dengan lebih cepat. Setiap kali pemicu DML diterapkan untuk tujuan audit, pastikan bahwa SET NOCOUNT ON pilihan digunakan secara efektif.

Di artikel berikutnya, kita akan membahas pemicu DDL dan Pemicu Logon.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Menggunakan prosedur tersimpan SQL Server dari Python (pyodbc)

  2. Menjelajahi batasan yang berbeda di SQL Server

  3. Sumber daya apa yang tersedia untuk penyetelan kinerja Database?

  4. Perbaiki Msg 241 "Konversi gagal saat mengonversi tanggal dan/atau waktu dari string karakter" di SQL Server

  5. DBA - Cara Membunuh Semua Proses Basis Data Di SQL Server