使用SQL Server Trigger的LOG系统

时间:2015-02-26 22:33:31

标签: sql sql-server sql-server-2005 triggers

我试图创建一个触发器来记录许多表中的任何更改。但现在,我只在一个名为" MAN_OS_TIPO"的表中进行测试。

目标:

我需要检测哪个列已被更改,并将OLD和NEW值放入日志表中" SYS_LOG_UPDATE"

PS:如果您知道另一种记录更新的方式,请告诉我

日志表:

  • 表格名称 [Tabela]
  • 列名称 [Coluna]
  • 旧值 [DadoAntigo]
  • 新值 [DadoNovo]
  • app用户 [Usuario]
  • 操作日期 [数据]

PS:此表将存储来自多个表的日志数据。

这是用于创建表的CODE:

USE [SIGO]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
DROP TABLE dbo.MAN_OS_TIPO    -- Just for test faster

/* CREATE */
CREATE TABLE dbo.MAN_OS_TIPO (
    Id int IDENTITY(1,1) NOT NULL,
    Descricao nvarchar(30) NOT NULL,
    /* System */
    LData datetime NULL,
    LUser int NULL,
    CData datetime NOT NULL,
    CUser int NULL
CONSTRAINT [PK_MAN_OS_TIPO] PRIMARY KEY NONCLUSTERED (
    [Id] ASC
) WITH (
    PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON
) ON [PRIMARY]
) ON [PRIMARY]
GO
/* DEFAULT */ ALTER TABLE dbo.MAN_OS_TIPO ADD CONSTRAINT DF_MAN_OS_TIPO_CDATA DEFAULT getdate() for [CData]
GO
/* UNIQUE */ ALTER TABLE dbo.MAN_OS_TIPO ADD CONSTRAINT UQ_MAN_OS_TIPO_DESCRICAO UNIQUE (Descricao)
GO

触发器

/* TRIGGER */
CREATE TRIGGER TR_MAN_OS_TIPO_UPDATE ON dbo.MAN_OS_TIPO
FOR UPDATE
AS
    DECLARE
        @OldValue nvarchar(max),    -- Valor antigo
        @NewValue nvarchar(max),    -- Valor novo
        @LUser int,                 -- Usuário que está alterando
        @Id int,            -- Id do registro


        @qtd int,               -- Quantity of column in table
        @cont int,              -- while Counter
        @tab nvarchar(max),     -- Name of table
        @col nvarchar(max),     -- Name of column
        @sql nvarchar(max),     -- SQL

    SET @cont = 1
    SET @tab = 'MAN_OS_TIPO'

    -- Count how many columns the table has
    SELECT @qtd = COUNT(*) FROM [INFORMATION_SCHEMA].[COLUMNS] WHERE TABLE_NAME = @tab


    WHILE (@cont <= @qtd)
    BEGIN
        SELECT @col = COLUMN_NAME FROM [INFORMATION_SCHEMA].[COLUMNS] WHERE     TABLE_NAME = @tab AND ORDINAL_POSITION = @cont

        IF (@col != 'Id' AND @col != 'CUser' AND @col != 'CData' AND @col !=    'LUser' AND @col != 'LData')
        BEGIN
            PRINT @col
            -- Get old values
            SELECT @Id = Id, @OldValue = CAST(convert(nvarchar,@col,103) AS     NVARCHAR) FROM DELETED

            -- Get new values
            SELECT @NewValue = CAST(convert(nvarchar,' + @col + ',103) AS NVARCHAR), @LUser = LUser FROM INSERTED

            PRINT 'old: ' + @OldValue + ' // new: ' + @NewValue    -- Just for debug
            IF (@NewValue != @OldValue)    -- Just if the value was changed
            BEGIN
                -- Insert in the log table
                INSERT INTO [dbo].[SYS_LOG_UPDATE] ([Tabela],[Coluna],  [DadoAntigo],[DadoNovo],[Usuario],[Data])
                    VALUES (@tab,@col,@OldValue,@NewValue,@LUser,getdate())
                PRINT 'LOG!'    -- Just for debug
            END
        END
        SET @cont = @cont + 1
    END
    SET @sql = 'UPDATE ' + @tab + ' SET [LData] = getdate() WHERE [Id] = ' +    CAST(@Id AS nvarchar)    -- Just inform the last update date
    PRINT @sql
    EXEC(@sql)
GO

此代码用于填充表格:

-- Insert new value
INSERT INTO [dbo].[MAN_OS_TIPO]
           ([Descricao]
           ,[CData]
           ,[CUser])
     VALUES
           ('Corretiva',
           getdate(),
           1)
GO

-- Update value
UPDATE [dbo].[MAN_OS_TIPO]
   SET [Descricao] = 'Corretiva A'
      ,[LUser] = 2
 WHERE [Descricao] = 'Corretiva'
GO

问题

当我试图获得旧价值时......

SELECT @Id = Id, @OldValue = CAST(convert(nvarchar,@col,103) AS     NVARCHAR) FROM DELETED

... @OldValue收到列的名称。但我需要在列中获取值。

我可以手动指定列的所有名称,但这会留下非常大的代码。

顺便说一下......如果你知道如何获取列的值或在日志表中注册所有更新,我很高兴。

0 个答案:

没有答案