仅将修改后的值和列名称插入表中

时间:2015-04-09 09:34:06

标签: sql sql-server tsql sql-server-2012

我有一个sql server 2012数据库。我有一个changeLog表包含 TableName, ColumnName, FromValueToValue列。这将用于跟踪修改的列和数据。

因此,如果通过应用程序进行任何更新,则只有修改过的列应该使用其新旧值插入此表中。

任何人都可以帮助我。

例如: 如果过程更新属性表的所有列(propertyName, address) 然后,如果用户更新propertyName(但更新还包含address列,但没有数据更改),则只有propertyName及其数据将插入ChangeLog表而不是{{1由于address数据不包含任何数据更改,因此列及其数据。

1 个答案:

答案 0 :(得分:1)

IF 根本没有其他审计要求 - 没有这个,你不会以任何方式考虑审计 - 那么好吧,去吧。然而,这是一个非常有限的审计使用:用户X在时间Y改变了这个字段。一般来说,这是一个更广泛的问题的一部分:用户X做了什么?数据库中的客户数据发生了什么,最终以现在的方式结束了?

如果您拥有自己建议的数据结构并且重建繁重,那么这样的问题就更难回答。我通常的做法如下。从像这样的基表开始(这来自我当前的一个项目):

CREATE TABLE [de].[Generation](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [LocalTime] [datetime] NOT NULL,
    [EntityId] [int] NOT NULL,
    [Generation] [decimal](18, 4) NOT NULL,
    [UpdatedAt] [datetime] NOT NULL CONSTRAINT [DF_Generation_UpdatedAt]  DEFAULT (getdate()),
 CONSTRAINT [PK_Generation] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)

(我已经排除了FK定义,因为它们在这里并不相关。)

首先为此表创建一个Audit表:

CREATE TABLE [de].[GenerationAudit](
    [AuditId] int identity(1, 1) not null,
    [Id] [int] NOT NULL,
    [LocalTimeOld] [datetime] NULL,
    [EntityIdOld] [int] NULL,
    [GenerationOld] [decimal](18, 4) null,
    [UpdatedAtOld] [datetime] null,
    [LocalTimeNew] [datetime] null,
    [EntityIdNew] [int] null,
    [GenerationNew] [decimal](18, 4) null,
    [UpdatedAtNew] [datetime] NOT NULL CONSTRAINT [DF_GenerationAudit_UpdatedAt]  DEFAULT (getdate()),
    [UpdatedBy] varchar(60) not null
 CONSTRAINT [PK_GenerationAudit] PRIMARY KEY CLUSTERED 
(
    [AuditId] ASC
)

此表格中每列的*旧版本和*版本都无法更改。作为IDENTITY PK的ID不能改变,所以不需要旧的/新的。我还添加了一个UpdatedBy列。它还有一个新的AuditId IDENTITY PK。

接下来在基表上创建三个触发器:一个用于INSERT,一个用于UPDATE,一个用于DELETE。在Insert触发器中,在Audit表中插入一行,其中从inserted表中选择New列,Old值为null。在UPDATE中,Oldvalues来自已删除而新来自插入。在DELETE触发器中,old from from deleted和new都是null。

UPDATE触发器如下所示:

CREATE TRIGGER GenerationAuditUpdate
   ON  de.Generation
   AFTER UPDATE
AS 
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    insert into de.GenerationAudit (Id, LocalTimeOld, EntityIdOld, GenerationOld, UpdatedAtOld,
                                        LocalTimeNew, EntityIdNew, GenerationNew, UpdatedAtNew,
                                        UpdatedBy)
    select isnull(i.Id, d.Id), d.LocalTime, d.EntityId, d.Generation, d.UpdatedAt,
                               i.LocalTime, i.EntityId, d.Generation, getdate(),
                               SYSTEM_USER)
    from inserted i
    full outer join deleted d on d.Id = i.Id;

END
GO

然后,您可以获得每个更改的完整前/后图片(并且它将比逐列分离差异更快)。您可以在Audit表上创建视图,以获取Old值与new不同的条目,并包括基表Id(您的结构中也需要它!),执行它的用户以及它们执行的时间它(UpdatedAtNew)。

那是我的审计版本,它是我的!