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

Pemicu di SQL Server - Selesaikan jenis Transaksi untuk Tabel Audit

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.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana cara mengelompokkan pada rentang berkelanjutan?

  2. Sql Server mengembalikan nilai kolom identitas setelah memasukkan pernyataan

  3. Lintasi semua kunci asing dalam basis data dan buat jalur

  4. Apa manfaat menggunakan sintaks Konstruktor Baris dalam pernyataan penyisipan T-Sql?

  5. Memodifikasi Pekerjaan Agen SQL Server (T-SQL)