Setelah Anda memperbaiki pemicu untuk mencakup ketiga operasi,
IF EXISTS (SELECT 1 FROM inserted)
BEGIN
IF EXISTS (SELECT 1 FROM deleted)
BEGIN
SET @action = 'UPDATE';
END
ELSE
BEGIN
SET @action = 'INSERT';
END
ELSE
BEGIN
SET @action = 'DELETE';
END
Alternatif lain adalah tiga pemicu terpisah, satu untuk setiap tindakan.
Berhati-hatilah terhadap MERGE jika Anda menggunakannya... Atau bersiaplah untuk itu saat Anda pindah ke SQL Server 2008 atau lebih.
EDIT
Saya pikir apa yang Anda cari adalah INSTEAD OF
memicu sebaliknya (betapa ironisnya). Berikut adalah salah satu contoh. Mari kita pertimbangkan tabel yang sangat sederhana dengan kolom PK dan kolom unik:
CREATE TABLE dbo.foobar(id INT PRIMARY KEY, x CHAR(1) UNIQUE);
GO
Dan tabel log sederhana untuk menangkap aktivitas:
CREATE TABLE dbo.myLog
(
foobar_id INT,
oldValue XML,
newValue XML,
[action] CHAR(6),
success BIT
);
GO
Berikut INSTEAD OF
pemicu akan mencegat INSERT/UPDATE/DELETE
perintah, mencoba mereplikasi pekerjaan yang akan mereka lakukan, dan mencatat apakah itu gagal atau berhasil:
CREATE TRIGGER dbo.foobar_inst
ON dbo.foobar
INSTEAD OF INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @action CHAR(6), @success BIT;
SELECT @action = 'DELETE', @success = 1;
IF EXISTS (SELECT 1 FROM inserted)
BEGIN
IF EXISTS (SELECT 1 FROM deleted)
SET @action = 'UPDATE';
ELSE
SET @action = 'INSERT';
END
BEGIN TRY
IF @action = 'INSERT'
INSERT dbo.foobar(id, x) SELECT id, x FROM inserted;
IF @action = 'UPDATE'
UPDATE f SET x = i.x FROM dbo.foobar AS f
INNER JOIN inserted AS i ON f.id = i.id;
IF @action = 'DELETE'
DELETE f FROM dbo.foobar AS f
INNER JOIN inserted AS i ON f.id = i.id;
END TRY
BEGIN CATCH
ROLLBACK; -- key part here!
SET @success = 0;
END CATCH
IF @action = 'INSERT'
INSERT dbo.myLog SELECT i.id, NULL,
(SELECT * FROM inserted WHERE id = i.id FOR XML PATH),
@action, @success FROM inserted AS i;
IF @action = 'UPDATE'
INSERT dbo.myLog SELECT i.id,
(SELECT * FROM deleted WHERE id = i.id FOR XML PATH),
(SELECT * FROM inserted WHERE id = i.id FOR XML PATH),
@action, @success FROM inserted AS i;
IF @action = 'DELETE'
INSERT dbo.myLog SELECT d.id,
(SELECT * FROM deleted WHERE id = d.id FOR XML PATH),
NULL, @action, @success FROM deleted AS d;
END
GO
Mari kita coba beberapa pernyataan transaksi implisit yang sangat sederhana:
-- these succeed:
INSERT dbo.foobar SELECT 1, 'x';
GO
INSERT dbo.foobar SELECT 2, 'y';
GO
-- fails with PK violation:
INSERT dbo.foobar SELECT 1, 'z';
GO
-- fails with UQ violation:
UPDATE dbo.foobar SET x = 'y' WHERE id = 1;
GO
Periksa lognya:
SELECT foobar_id, oldValue, newValue, action, success FROM dbo.myLog;
Hasil:
foobar_id oldValue newValue action success
--------- ----------------------------- ----------------------------- ------ -------
1 NULL <row><id>1</id><x>x</x></row> INSERT 1
2 NULL <row><id>2</id><x>y</x></row> INSERT 1
1 NULL <row><id>1</id><x>z</x></row> INSERT 0
1 <row><id>1</id><x>x</x></row> <row><id>1</id><x>y</x></row> UPDATE 0
Tentu saja Anda mungkin menginginkan kolom lain di tabel log, seperti pengguna, tanggal/waktu, bahkan mungkin pernyataan aslinya. Ini tidak dimaksudkan sebagai solusi audit yang sepenuhnya komprehensif, hanya sebagai contoh.
Seperti yang ditunjukkan Mikael, ini bergantung pada fakta bahwa batch luar adalah satu perintah yang memulai transaksi implisit. Perilaku harus diuji jika kumpulan luar adalah transaksi multi-pernyataan yang eksplisit.
Perhatikan juga bahwa ini tidak menangkap "kegagalan" dalam kasus di mana, katakanlah, UPDATE memengaruhi nol baris. Jadi, Anda perlu mendefinisikan secara eksplisit apa arti "kegagalan" - dalam beberapa kasus Anda mungkin perlu membangun penanganan kegagalan Anda sendiri di kode luar, bukan di pemicu.