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

Pemicu Pembaruan SQL Server, Dapatkan Hanya bidang yang dimodifikasi

Saya memiliki solusi lain yang sama sekali berbeda yang tidak menggunakan COLUMNS_UPDATED sama sekali, juga tidak bergantung pada membangun SQL dinamis saat runtime. (Anda mungkin ingin menggunakan SQL dinamis pada waktu desain tetapi itu cerita lain.)

Pada dasarnya Anda mulai dengan tabel yang dimasukkan dan dihapus, unpivot masing-masing sehingga Anda hanya memiliki kunci unik, nilai bidang, dan kolom nama bidang untuk masing-masing. Kemudian Anda bergabung dengan keduanya dan memfilter apa pun yang berubah.

Berikut adalah contoh kerja lengkap, termasuk beberapa panggilan uji untuk menunjukkan apa yang dicatat.

-- -------------------- Setup tables and some initial data --------------------
CREATE TABLE dbo.Sample_Table (ContactID int, Forename varchar(100), Surname varchar(100), Extn varchar(16), Email varchar(100), Age int );
INSERT INTO Sample_Table VALUES (1,'Bob','Smith','2295','[email protected]',24);
INSERT INTO Sample_Table VALUES (2,'Alice','Brown','2255','[email protected]',32);
INSERT INTO Sample_Table VALUES (3,'Reg','Jones','2280','[email protected]',19);
INSERT INTO Sample_Table VALUES (4,'Mary','Doe','2216','[email protected]',28);
INSERT INTO Sample_Table VALUES (5,'Peter','Nash','2214','[email protected]',25);

CREATE TABLE dbo.Sample_Table_Changes (ContactID int, FieldName sysname, FieldValueWas sql_variant, FieldValueIs sql_variant, modified datetime default (GETDATE()));

GO

-- -------------------- Create trigger --------------------
CREATE TRIGGER TriggerName ON dbo.Sample_Table FOR DELETE, INSERT, UPDATE AS
BEGIN
    SET NOCOUNT ON;
    --Unpivot deleted
    WITH deleted_unpvt AS (
        SELECT ContactID, FieldName, FieldValue
        FROM 
           (SELECT ContactID
                , cast(Forename as sql_variant) Forename
                , cast(Surname as sql_variant) Surname
                , cast(Extn as sql_variant) Extn
                , cast(Email as sql_variant) Email
                , cast(Age as sql_variant) Age
           FROM deleted) p
        UNPIVOT
           (FieldValue FOR FieldName IN 
              (Forename, Surname, Extn, Email, Age)
        ) AS deleted_unpvt
    ),
    --Unpivot inserted
    inserted_unpvt AS (
        SELECT ContactID, FieldName, FieldValue
        FROM 
           (SELECT ContactID
                , cast(Forename as sql_variant) Forename
                , cast(Surname as sql_variant) Surname
                , cast(Extn as sql_variant) Extn
                , cast(Email as sql_variant) Email
                , cast(Age as sql_variant) Age
           FROM inserted) p
        UNPIVOT
           (FieldValue FOR FieldName IN 
              (Forename, Surname, Extn, Email, Age)
        ) AS inserted_unpvt
    )

    --Join them together and show what's changed
    INSERT INTO Sample_Table_Changes (ContactID, FieldName, FieldValueWas, FieldValueIs)
    SELECT Coalesce (D.ContactID, I.ContactID) ContactID
        , Coalesce (D.FieldName, I.FieldName) FieldName
        , D.FieldValue as FieldValueWas
        , I.FieldValue AS FieldValueIs 
    FROM 
        deleted_unpvt d

            FULL OUTER JOIN 
        inserted_unpvt i
            on      D.ContactID = I.ContactID 
                AND D.FieldName = I.FieldName
    WHERE
         D.FieldValue <> I.FieldValue --Changes
        OR (D.FieldValue IS NOT NULL AND I.FieldValue IS NULL) -- Deletions
        OR (D.FieldValue IS NULL AND I.FieldValue IS NOT NULL) -- Insertions
END
GO
-- -------------------- Try some changes --------------------
UPDATE Sample_Table SET age = age+1;
UPDATE Sample_Table SET Extn = '5'+Extn where Extn Like '221_';

DELETE FROM Sample_Table WHERE ContactID = 3;

INSERT INTO Sample_Table VALUES (6,'Stephen','Turner','2299','[email protected]',25);

UPDATE Sample_Table SET ContactID = 7 where ContactID = 4; --this will be shown as a delete and an insert
-- -------------------- See the results --------------------
SELECT *, SQL_VARIANT_PROPERTY(FieldValueWas, 'BaseType') FieldBaseType, SQL_VARIANT_PROPERTY(FieldValueWas, 'MaxLength') FieldMaxLength from Sample_Table_Changes;

-- -------------------- Cleanup --------------------
DROP TABLE dbo.Sample_Table; DROP TABLE dbo.Sample_Table_Changes;

Jadi tidak perlu dipusingkan dengan masalah bigint bitfields dan arth overflow. Jika Anda mengetahui kolom yang ingin Anda bandingkan pada waktu desain, maka Anda tidak memerlukan SQL dinamis.

Pada sisi negatifnya, output dalam format yang berbeda dan semua nilai bidang dikonversi ke sql_variant, yang pertama dapat diperbaiki dengan memutar output lagi, dan yang kedua dapat diperbaiki dengan menyusun kembali ke jenis yang diperlukan berdasarkan pengetahuan Anda tentang desain tabel, tetapi keduanya memerlukan beberapa sql dinamis yang kompleks. Kedua hal ini mungkin tidak menjadi masalah dalam keluaran XML Anda. Pertanyaan ini melakukan sesuatu yang mirip dengan mendapatkan output kembali dalam format yang sama.

Sunting:Tinjau komentar di bawah, jika Anda memiliki kunci utama alami yang dapat berubah maka Anda masih dapat menggunakan metode ini. Anda hanya perlu menambahkan kolom yang diisi secara default dengan GUID menggunakan fungsi NEWID(). Anda kemudian menggunakan kolom ini sebagai pengganti kunci utama.

Anda mungkin ingin menambahkan indeks ke bidang ini, tetapi karena tabel yang dihapus dan dimasukkan dalam pemicu ada di memori, hal itu mungkin tidak akan digunakan dan mungkin berdampak negatif pada kinerja.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cara Mengekspor hasil kueri ke .csv atau File Tab Delimited di SQL Server Management Studio(SSMS) - Tutorial SQL Server / TSQL Bagian 23

  2. Definisi laporan SSRS lebih baru dari Server

  3. Sintaks salah di dekat kata kunci 'dengan'...pernyataan sebelumnya harus diakhiri dengan titik koma

  4. Menghubungkan SQL Server ke Database Java

  5. @@IDENTITY, SCOPE_IDENTITY(), OUTPUT dan metode lain untuk mengambil identitas terakhir