sql >> データベース >  >> RDS >> Sqlserver

SQL Server履歴テーブル-SPまたはトリガーを介してデータを入力しますか?

    トリガー。

    GUIを作成しました(内部では Red Matrix Reloaded と呼ばれます) )監査ログトリガーの簡単な作成/管理を可能にします。

    使用されているもののいくつかのDDLは次のとおりです:

    AuditLogテーブル

    CREATE TABLE [AuditLog] (
        [AuditLogID] [int] IDENTITY (1, 1) NOT NULL ,
        [ChangeDate] [datetime] NOT NULL CONSTRAINT [DF_AuditLog_ChangeDate] DEFAULT (getdate()),
        [RowGUID] [uniqueidentifier] NOT NULL ,
        [ChangeType] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
        [TableName] [varchar] (128) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
        [FieldName] [varchar] (128) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
        [OldValue] [varchar] (8000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
        [NewValue] [varchar] (8000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
        [Username] [varchar] (128) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
        [Hostname] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
        [AppName] [varchar] (128) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
        [UserGUID] [uniqueidentifier] NULL ,
        [TagGUID] [uniqueidentifier] NULL ,
        [Tag] [varchar] (8000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL 
    )
    

    挿入をログに記録するトリガー

    CREATE TRIGGER LogInsert_Nodes ON dbo.Nodes
    FOR INSERT
    AS
    
    /* Load the saved context info UserGUID */
    DECLARE @SavedUserGUID uniqueidentifier
    
    SELECT @SavedUserGUID = CAST(context_info as uniqueidentifier)
    FROM master.dbo.sysprocesses
    WHERE spid = @@SPID
    
    DECLARE @NullGUID uniqueidentifier
    SELECT @NullGUID = '{00000000-0000-0000-0000-000000000000}'
    
    IF @SavedUserGUID = @NullGUID
    BEGIN
        SET @SavedUserGUID = NULL
    END
    
        /*We dont' log individual field changes Old/New because the row is new.
        So we only have one record - INSERTED*/
    
        INSERT INTO AuditLog(
                ChangeDate, RowGUID, ChangeType, 
                Username, HostName, AppName,
                UserGUID, 
                TableName, FieldName, 
                TagGUID, Tag, 
                OldValue, NewValue)
    
        SELECT
            getdate(), --ChangeDate
            i.NodeGUID, --RowGUID
            'INSERTED', --ChangeType
            USER_NAME(), HOST_NAME(), APP_NAME(), 
            @SavedUserGUID, --UserGUID
            'Nodes', --TableName
            '', --FieldName
            i.ParentNodeGUID, --TagGUID
            i.Caption, --Tag
            null, --OldValue
            null --NewValue
        FROM Inserted i
    

    更新をログに記録するトリガー

    CREATE TRIGGER LogUpdate_Nodes ON dbo.Nodes
    FOR UPDATE AS
    
    /* Load the saved context info UserGUID */
    DECLARE @SavedUserGUID uniqueidentifier
    
    SELECT @SavedUserGUID = CAST(context_info as uniqueidentifier)
    FROM master.dbo.sysprocesses
    WHERE spid = @@SPID
    
    DECLARE @NullGUID uniqueidentifier
    SELECT @NullGUID = '{00000000-0000-0000-0000-000000000000}'
    
    IF @SavedUserGUID = @NullGUID
    BEGIN
        SET @SavedUserGUID = NULL
    END
    
        /* ParentNodeGUID uniqueidentifier */
        IF UPDATE (ParentNodeGUID)
        BEGIN
            INSERT INTO AuditLog(
                ChangeDate, RowGUID, ChangeType, 
                Username, HostName, AppName,
                UserGUID, 
                TableName, FieldName, 
                TagGUID, Tag, 
                OldValue, NewValue)
            SELECT 
                getdate(), --ChangeDate
                i.NodeGUID, --RowGUID
                'UPDATED', --ChangeType
                USER_NAME(), HOST_NAME(), APP_NAME(), 
                @SavedUserGUID, --UserGUID
                'Nodes', --TableName
                'ParentNodeGUID', --FieldName
                i.ParentNodeGUID, --TagGUID
                i.Caption, --Tag
                d.ParentNodeGUID, --OldValue
                i.ParentNodeGUID --NewValue
            FROM Inserted i
                INNER JOIN Deleted d
                ON i.NodeGUID = d.NodeGUID
            WHERE (d.ParentNodeGUID IS NULL AND i.ParentNodeGUID IS NOT NULL)
            OR (d.ParentNodeGUID IS NOT NULL AND i.ParentNodeGUID IS NULL)
            OR (d.ParentNodeGUID <> i.ParentNodeGUID)
        END
    
        /* Caption varchar(255) */
        IF UPDATE (Caption)
        BEGIN
            INSERT INTO AuditLog(
                ChangeDate, RowGUID, ChangeType, 
                Username, HostName, AppName,
                UserGUID, 
                TableName, FieldName, 
                TagGUID, Tag, 
                OldValue, NewValue)
            SELECT 
                getdate(), --ChangeDate
                i.NodeGUID, --RowGUID
                'UPDATED', --ChangeType
                USER_NAME(), HOST_NAME(), APP_NAME(), 
                @SavedUserGUID, --UserGUID
                'Nodes', --TableName
                'Caption', --FieldName
                i.ParentNodeGUID, --TagGUID
                i.Caption, --Tag
                d.Caption, --OldValue
                i.Caption --NewValue
            FROM Inserted i
                INNER JOIN Deleted d
                ON i.NodeGUID = d.NodeGUID
            WHERE (d.Caption IS NULL AND i.Caption IS NOT NULL)
            OR (d.Caption IS NOT NULL AND i.Caption IS NULL)
            OR (d.Caption <> i.Caption)
        END
    
    ...
    
    /* ImageGUID uniqueidentifier */
    IF UPDATE (ImageGUID)
    BEGIN
        INSERT INTO AuditLog(
            ChangeDate, RowGUID, ChangeType, 
            Username, HostName, AppName,
            UserGUID, 
            TableName, FieldName, 
            TagGUID, Tag, 
            OldValue, NewValue)
        SELECT 
            getdate(), --ChangeDate
            i.NodeGUID, --RowGUID
            'UPDATED', --ChangeType
            USER_NAME(), HOST_NAME(), APP_NAME(), 
            @SavedUserGUID, --UserGUID
            'Nodes', --TableName
            'ImageGUID', --FieldName
            i.ParentNodeGUID, --TagGUID
            i.Caption, --Tag
            (SELECT Caption FROM Nodes WHERE NodeGUID = d.ImageGUID), --OldValue
            (SELECT Caption FROM Nodes WHERE NodeGUID = i.ImageGUID) --New Value
        FROM Inserted i
            INNER JOIN Deleted d
            ON i.NodeGUID = d.NodeGUID
        WHERE (d.ImageGUID IS NULL AND i.ImageGUID IS NOT NULL)
        OR (d.ImageGUID IS NOT NULL AND i.ImageGUID IS NULL)
        OR (d.ImageGUID <> i.ImageGUID)
    END
    

    ログ削除のトリガー

    CREATE TRIGGER LogDelete_Nodes ON dbo.Nodes
    FOR DELETE
    AS
    
    /* Load the saved context info UserGUID */
    DECLARE @SavedUserGUID uniqueidentifier
    
    SELECT @SavedUserGUID = CAST(context_info as uniqueidentifier)
    FROM master.dbo.sysprocesses
    WHERE spid = @@SPID
    
    DECLARE @NullGUID uniqueidentifier
    SELECT @NullGUID = '{00000000-0000-0000-0000-000000000000}'
    
    IF @SavedUserGUID = @NullGUID
    BEGIN
        SET @SavedUserGUID = NULL
    END
    
        /*We dont' log individual field changes Old/New because the row is new.
        So we only have one record - DELETED*/
    
        INSERT INTO AuditLog(
                ChangeDate, RowGUID, ChangeType, 
                Username, HostName, AppName,
                UserGUID, 
                TableName, FieldName, 
                TagGUID, Tag, 
                OldValue,NewValue)
    
        SELECT
            getdate(), --ChangeDate
            d.NodeGUID, --RowGUID
            'DELETED', --ChangeType
            USER_NAME(), HOST_NAME(), APP_NAME(), 
            @SavedUserGUID, --UserGUID
            'Nodes', --TableName
            '', --FieldName
            d.ParentNodeGUID, --TagGUID
            d.Caption, --Tag
            null, --OldValue
            null --NewValue
        FROM Deleted d
    

    また、ソフトウェアのどのユーザーが更新を行ったかを知るために、すべての接続はストアドプロシージャを呼び出して「SQLServerにログオン」します。

    CREATE PROCEDURE dbo.SaveContextUserGUID @UserGUID uniqueidentifier AS
    
    /* Saves the given UserGUID as the session's "Context Information" */
    IF @UserGUID IS NULL
    BEGIN
        PRINT 'Emptying CONTEXT_INFO because of null @UserGUID'
        DECLARE @BinVar varbinary(128)
        SET @BinVar = CAST( REPLICATE( 0x00, 128 ) AS varbinary(128) )
        SET CONTEXT_INFO @BinVar
        RETURN 0
    END
    
    DECLARE @UserGUIDBinary binary(16) --a guid is 16 bytes
    SELECT @UserGUIDBinary = CAST(@UserGUID as binary(16))
    SET CONTEXT_INFO @UserGUIDBinary
    
    
    /* To load the guid back 
    DECLARE @SavedUserGUID uniqueidentifier
    
    SELECT @SavedUserGUID = CAST(context_info as uniqueidentifier)
    FROM master.dbo.sysprocesses
    WHERE spid = @@SPID
    
    select @SavedUserGUID AS UserGUID
    */
    

    メモ

    • Stackoverflowコードフォーマットはほとんどの空白行を削除します-したがって、フォーマットは最悪です
    • 統合セキュリティではなく、ユーザーのテーブルを使用します
    • このコードは便宜のために提供されています-私たちのデザイン選択に対する批判は許されていません。純粋主義者は、すべてのロギングコードはビジネスレイヤーで実行する必要があると主張するかもしれません。ここに来て、私たちのためにそれを記述/保守することができます。
    • BLOBは、SQL Serverのトリガーを使用してログに記録することはできません(BLOBの「前」バージョンはありません-あるものだけがあります)。 TextとnTextはblobであり、メモをログに記録できないようにするか、varchar(2000)のものにします。
    • [タグ]列は、行を識別するための任意のテキストとして使用されます(たとえば、顧客が削除された場合、タグには監査ログテーブルに「GeneralMotorsNorthAmerica」と表示されます。
    • TagGUIDは、行の「親」を指すために使用されます。たとえば、 InvoiceLineItemsのログ記録 InvoiceHeaderを指す 。このようにして、特定の請求書に関連する監査ログエントリを検索する人は、監査証跡の広告申込情報のTagGUIDによって削除された「広告申込情報」を見つけることができます。
    • 「OldValue」と「NewValue」の値は、意味のある文字列を取得するために、副選択として記述される場合があります。つまり、 "

      OldValue:{233d-ad34234 ..} NewValue:{883-sdf34 ...}

    監査証跡では、以下よりも有用性が低くなります:

    OldValue: Daimler Chrysler
    NewValue: Cerberus Capital Management
    

    最後のメモ :私たちがしていることをしないでください。これは私たちにとっては素晴らしいことですが、他の人は自由に使用できません。



    1. pipのインストールが/usr/ bin / clangで失敗する:そのようなファイルやディレクトリはありません

    2. SYSDATETIMEOFFSET()SQL Server(T-SQL)の例

    3. Python FlaskとMySQLを使用してゼロからWebアプリを作成する:パート2

    4. MySQLエラー1215:外部キー制約を追加できません