2013-04-11 3 views
0

SQL Server에 트리거를 만들어 업데이트 된 열만 테이블 이름, 열 이름, 이전/새 값, 날짜, 시간 및 특정 테이블에 대한 사용자가있는 감사 테이블에 작성해야합니다. 어떻게해야합니까?SQL Server 자동 감사 업데이트 된 열

답변

6

내가 일반적으로 감사 데이터 를 저장하기 위해이 같은 테이블이와 나는https://www.simple-talk.com/sql/database-administration/pop-rivetts-sql-server-faq-no.5-pop-on-the-audit-trail/

CREATE TABLE [dbo].[Audit](
    [AuditID] [int] IDENTITY(1,1) NOT NULL, 
    [Type] [char](1) NULL, 
    [TableName] [varchar](128) NULL, 
    [PK] [varchar](1000) NULL, 
    [FieldName] [varchar](128) NULL, 
    [OldValue] [varchar](1000) NULL, 
    [NewValue] [varchar](1000) NULL, 
    [UpdateDate] [datetime] NULL, 
    [UserName] [varchar](128) NULL, 
CONSTRAINT [PK_Audit] PRIMARY KEY CLUSTERED 
(
    [AuditID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

여기에서이 솔루션을 가지고 그리고 내가

을 감사 할 모든 테이블에 다음 트리거를 추가
CREATE TRIGGER [dbo].[Tr_DB_Audit] ON [dbo].['YourTableName'] FOR INSERT, UPDATE, DELETE 
AS 

DECLARE @bit INT , 
     @field INT , 
     @maxfield INT , 
     @char INT , 
     @fieldname VARCHAR(128) , 
     @TableName VARCHAR(128) , 
     @PKCols VARCHAR(1000) , 
     @sql VARCHAR(2000), 
     @UpdateDate VARCHAR(21) , 
     @UserName VARCHAR(128) , 
     @Type CHAR(1) , 
     @PKSelect VARCHAR(1000) 


--You will need to change @TableName to match the table to be audited 
SELECT @TableName = 'NameOfTableYouWantToAudit' 

-- date and user 
SELECT   @UserName = SYSTEM_USER , 
     @UpdateDate = CONVERT(VARCHAR(8), GETDATE(), 112) 
       + ' ' + CONVERT(VARCHAR(12), GETDATE(), 114) 

-- Action 
IF EXISTS (SELECT * FROM inserted) 
     IF EXISTS (SELECT * FROM deleted) 
       SELECT @Type = 'U' 
     ELSE 
       SELECT @Type = 'I' 
ELSE 
     SELECT @Type = 'D' 

-- get list of columns 
SELECT * INTO #ins FROM inserted 
SELECT * INTO #del FROM deleted 

-- Get primary key columns for full outer join 
SELECT @PKCols = COALESCE(@PKCols + ' and', ' on') 
       + ' i.' + c.COLUMN_NAME + ' = d.' + c.COLUMN_NAME 
     FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk , 

       INFORMATION_SCHEMA.KEY_COLUMN_USAGE c 
     WHERE pk.TABLE_NAME = @TableName 
     AND  CONSTRAINT_TYPE = 'PRIMARY KEY' 
     AND  c.TABLE_NAME = pk.TABLE_NAME 
     AND  c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME 

-- Get primary key select for insert 
SELECT @PKSelect = COALESCE(@PKSelect+'+','') 
     + '''<' + COLUMN_NAME 
     + '=''+convert(varchar(100), 
coalesce(i.' + COLUMN_NAME +',d.' + COLUMN_NAME + '))+''>''' 
     FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk , 
       INFORMATION_SCHEMA.KEY_COLUMN_USAGE c 
     WHERE pk.TABLE_NAME = @TableName 
     AND  CONSTRAINT_TYPE = 'PRIMARY KEY' 
     AND  c.TABLE_NAME = pk.TABLE_NAME 
     AND  c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME 

IF @PKCols IS NULL 
BEGIN 
     RAISERROR('no PK on table %s', 16, -1, @TableName) 
     RETURN 
END 

SELECT   @field = 0, 
     @maxfield = MAX(ORDINAL_POSITION) 
     FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @TableName 
WHILE @field < @maxfield 
BEGIN 
     SELECT @field = MIN(ORDINAL_POSITION) 
       FROM INFORMATION_SCHEMA.COLUMNS 
       WHERE TABLE_NAME = @TableName 
       AND ORDINAL_POSITION > @field 
     SELECT @bit = (@field - 1)% 8 + 1 
     SELECT @bit = POWER(2,@bit - 1) 
     SELECT @char = ((@field - 1)/8) + 1 
     IF SUBSTRING(COLUMNS_UPDATED(),@char, 1) & @bit > 0 
             OR @Type IN ('I','D') 
     BEGIN 
       SELECT @fieldname = COLUMN_NAME 
         FROM INFORMATION_SCHEMA.COLUMNS 
         WHERE TABLE_NAME = @TableName 
         AND ORDINAL_POSITION = @field 
       SELECT @sql = ' 
insert Audit ( Type, 
       TableName, 
       PK, 
       FieldName, 
       OldValue, 
       NewValue, 
       UpdateDate, 
       UserName) 
select ''' + @Type + ''',''' 
     + @TableName + ''',' + @PKSelect 
     + ',''' + @fieldname + '''' 
     + ',convert(varchar(1000),d.' + @fieldname + ')' 
     + ',convert(varchar(1000),i.' + @fieldname + ')' 
     + ',''' + @UpdateDate + '''' 
     + ',''' + @UserName + '''' 
     + ' from #ins i full outer join #del d' 
     + @PKCols 
     + ' where i.' + @fieldname + ' <> d.' + @fieldname 
     + ' or (i.' + @fieldname + ' is null and d.' 
           + @fieldname 
           + ' is not null)' 
     + ' or (i.' + @fieldname + ' is not null and d.' 
           + @fieldname 
           + ' is null)' 
       EXEC (@sql) 
     END 
END 

http://weblogs.asp.net/jgalloway/archive/2008/01/27/adding-simple-trigger-based-auditing-to-your-sql-server-database.aspx

+0

위대한 작품! 감사 ! – user2268955

+0

좋습니다. 답으로 표시해야합니다. – StackTrace

7

우리는 감사가 필요한 테이블이 많기 때문에 타사 도구 ApexSQL Audit을 사용하여 감사 트리거를 생성합니다.

타사 도구가 필요하지 않은 경우 평가판 모드에서이 도구를 사용하여 트리거 및 저장소 테이블을 어떻게 구현하는지 확인할 수 있습니다.

다음은 데이터베이스에서 신속하게 가져온 샘플 트리거 및 저장 테이블입니다.

데이터 스토리지 테이블 : 거래에 대한 세부 정보를 저장

enter image description here

테이블 : 여기

enter image description here

은 삭제 트리거의 샘플입니다. 댓글을 메모로 작성

CREATE TRIGGER [dbo].[tr_d_AUDIT_Table_Name] 
ON [dbo].[Table_Name] 
FOR DELETE 
NOT FOR REPLICATION 
AS 

BEGIN 
    DECLARE 
     @IDENTITY_SAVE    varchar(50), 
     @AUDIT_LOG_TRANSACTION_ID  Int, 
     @PRIM_KEY    nvarchar(4000), 
     @ROWS_COUNT    int 

    SET NOCOUNT ON 


    Select @ROWS_COUNT=count(*) from deleted 
    Set @IDENTITY_SAVE = CAST(IsNull(@@IDENTITY,1) AS varchar(50)) 

    INSERT 
    INTO dbo.AUDIT_LOG_TRANSACTIONS 
    (
     TABLE_NAME, 
     TABLE_SCHEMA, 
     AUDIT_ACTION_ID, 
     HOST_NAME, 
     APP_NAME, 
     MODIFIED_BY, 
     MODIFIED_DATE, 
     AFFECTED_ROWS, 
     [DATABASE] 
    ) 
    values(
     'Table_Name', 
     'dbo', 
     3, 
     CASE 
      WHEN LEN(HOST_NAME()) < 1 THEN ' ' 
      ELSE HOST_NAME() 
     END, 
     CASE 
      WHEN LEN(APP_NAME()) < 1 THEN ' ' 
      ELSE APP_NAME() 
     END, 
     SUSER_SNAME(), 
     GETDATE(), 
     @ROWS_COUNT, 
     'database_name' 
    ) 

    Set @AUDIT_LOG_TRANSACTION_ID = SCOPE_IDENTITY() 

    INSERT 
    INTO dbo.AUDIT_LOG_DATA 
    (
     AUDIT_LOG_TRANSACTION_ID, 
     PRIMARY_KEY_DATA, 
     COL_NAME, 
     OLD_VALUE_LONG, 
     DATA_TYPE 
     , KEY1 
    ) 
    SELECT 
     @AUDIT_LOG_TRANSACTION_ID, 
     convert(nvarchar(1500), IsNull('[Order_ID]='+CONVERT(nvarchar(4000), OLD.[Order_ID], 0), '[Order_ID] Is Null')), 
     'Order_ID', 
     CONVERT(nvarchar(4000), OLD.[Order_ID], 0), 
     'A' 
     , CONVERT(nvarchar(500), CONVERT(nvarchar(4000), OLD.[Order_ID], 0)) 
    FROM deleted OLD 
    WHERE 
     OLD.[Order_ID] Is Not Null 

    /* 
     Insert statement above is replicated for each column being audited 
    */ 

END 
관련 문제