Sqlserver
 sql >> डेटाबेस >  >> RDS >> Sqlserver

SQL सर्वर में ट्रिगर - ऑडिट टेबल के लिए किए गए लेन-देन का प्रकार प्राप्त करें

एक बार जब आप तीनों ऑपरेशनों को कवर करने के लिए अपना ट्रिगर ठीक कर लेते हैं,

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

एक अन्य विकल्प तीन अलग-अलग ट्रिगर हैं, प्रत्येक क्रिया के लिए एक।

यदि आप इसका उपयोग कर रहे हैं तो MERGE से सावधान रहें... या जब आप SQL Server 2008 या उससे आगे जाते हैं तो इसके लिए तैयार रहें।

संपादित करें

मुझे लगता है कि आप जो हो सकते हैं वह एक INSTEAD OF है इसके बजाय ट्रिगर (कितना विडंबनापूर्ण)। यहाँ एक उदाहरण है। आइए एक पीके कॉलम और एक अद्वितीय कॉलम के साथ एक बहुत ही सरल तालिका पर विचार करें:

CREATE TABLE dbo.foobar(id INT PRIMARY KEY, x CHAR(1) UNIQUE);
GO

और गतिविधि को पकड़ने के लिए एक साधारण लॉग टेबल:

CREATE TABLE dbo.myLog
(
    foobar_id INT, 
    oldValue  XML, 
    newValue  XML, 
    [action]  CHAR(6), 
    success   BIT
);
GO

निम्नलिखित INSTEAD OF ट्रिगर इंटरसेप्ट करेगा INSERT/UPDATE/DELETE आदेश, उनके द्वारा किए गए कार्य को दोहराने का प्रयास करें, और लॉग इन करें कि क्या यह विफलता या सफलता थी:

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

आइए कुछ बहुत ही सरल, निहित-लेनदेन कथनों को आजमाएं:

-- 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

लॉग की जाँच करें:

SELECT foobar_id, oldValue, newValue, action, success FROM dbo.myLog;

परिणाम:

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

बेशक आप शायद लॉग टेबल पर अन्य कॉलम चाहते हैं, जैसे उपयोगकर्ता, दिनांक/समय, यहां तक ​​​​कि मूल विवरण भी। यह पूरी तरह से व्यापक ऑडिटिंग समाधान नहीं था, बस एक उदाहरण है।

जैसा कि मिकेल बताते हैं, यह इस तथ्य पर निर्भर करता है कि बाहरी बैच एक एकल कमांड है जो एक अंतर्निहित लेनदेन शुरू करता है। व्यवहार का परीक्षण करना होगा यदि बाहरी बैच एक स्पष्ट, बहु-कथन लेनदेन है।

यह भी ध्यान दें कि यह उस मामले में "विफलता" पर कब्जा नहीं करता है, जहां कहें, एक अद्यतन शून्य पंक्तियों को प्रभावित करता है। तो आपको स्पष्ट रूप से परिभाषित करने की आवश्यकता है कि "विफलता" का क्या अर्थ है - कुछ मामलों में आपको बाहरी कोड में अपनी विफलता प्रबंधन बनाने की आवश्यकता हो सकती है, ट्रिगर में नहीं।




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL सर्वर 2012 से sqlalchemy और pyodbc का उपयोग करके कनेक्ट करना

  2. SQL में तालिका पंक्तियों के लिए सीमा निर्धारित करें

  3. परिमित कुल के प्रतिशत का सही आंकलन कैसे करें

  4. मैं एक लिंक किए गए सर्वर के साथ आसानी से टीवीपी का उपयोग कैसे कर सकता हूं?

  5. xml स्ट्रिंग मान वाले फ़ील्ड वाली सभी तालिकाएँ खोजें