【问题标题】:SQL Server triggers - insert new rows into audit tableSQL Server 触发器 - 将新行插入审计表
【发布时间】:2020-11-07 08:03:23
【问题描述】:

我有一个简单的表格,如下所示。

我想创建一个触发器以将新值插入“SectionsAudit”表中。

意思:

  1. 如果在Sections 表中插入新行,我想在Audit 表中插入同一行
  2. 如果在Sections 表中更新了现有行,我想在Audit 表中使用更新后的行创建一个新行。

如何在 SQL Server 中做到这一点?另外,我想知道这是否是一个好习惯?

CREATE TABLE [dbo].[Sections]  
(
    [Id]               int IDENTITY(1,1) NOT NULL,
    [Name]             varchar(25) NOT NULL,
    [InsertedBy]       varchar(25) NOT NULL,
    [InsertedDateTime] datetime NOT NULL,
    [UpdatedBy]        varchar(25) NOT NULL,
    [UpdatedDateTime]  datetime NOT NULL,

    CONSTRAINT [PK_Id] PRIMARY KEY CLUSTERED([Id])
) 

【问题讨论】:

标签: sql sql-server database-trigger


【解决方案1】:

触发器看起来像这样,这是一个很好的做法,具体取决于您使用的 MS SQL 版本。 请注意,要使用这种方法,必须在 dbo.SectionsAudit 中有一个字段来跟踪原始记录的 ModificationId(在示例中我称之为 IdModi)

CREATE TRIGGER [dbo].[tr_SectionsAudit]
    ON  [dbo].[Sections]
    AFTER INSERT, UPDATE
    NOT FOR REPLICATION
AS 
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    INSERT      SectionsAudit
                (Id, IdModi, fieldname, ...)
    SELECT      Id, IdModi = (ISNULL((SELECT    ISNULL(MAX(SA.IdModi), 0)
                                                    FROM    SectionsAudit SA 
                                                    WHERE   SA.Id = I.Id
                                                    ) , 0) + 1),
                fieldname, ...
    FROM        INSERTED I 
    

END

【讨论】:

  • 能否请您从选择中解释一下(我不明白 ISNULL 部分)。另外,INSERTED I after from 是什么?
  • @Chatra isnull 部分只是将 IdModi 初始化为 0 并求和 1,因此 IdModi 就像 SectionsAudit 表上的 identity(1,1) 字段。 INSERTED I 指的是 Sections 表中插入或修改的行。触发器只是在您的 SectionsAudit 表中执行插入,从 Sections 表上的插入/更新行中选择所有值,并使用 IdModi 将具有的子查询进行计算。
  • 我创建了审计表并拥有身份。我只写了简单的选择而不是 IdModi,它工作得很好。我想知道它失败的地方
  • 还有NOT FOR REPLICATION的作用是什么?
  • 如果你做了一个身份 (1,1),它在我的示例中不符合 IdModi 的目的,像 IdModi 这样的列用于识别/排序对部分中的单行所做的更改数量表,您创建的标识只是一个增量积分器,它不关心修改了哪一行,它总是做 id+1。 NOT FOR REPLICATION 选项指示 SQL Server 在作为复制过程的一部分进行数据修改时不触发触发器。看到这个sqlservertutorial.net/sql-server-triggers/…
【解决方案2】:

在您的情况下,我建议您使用 Rowversion 或 Change Data Capture。 下面是一些选项:

Rowversion

它是一个唯一的 8 个字节的二进制数。每次插入或更新任何记录的任何列时都会更新它

例子:

CREATE TABLE dbo.Test (ID int PRIMARY KEY, RowVersion rowversion) ;

Change Data Capture

更改数据捕获记录应用于 SQL Server 表的插入、更新和删除活动。这使得更改的详细信息以易于使用的关系格式提供。为修改的行捕获列信息和将更改应用于目标环境所需的元数据,并将其存储在反映跟踪源表的列结构的更改表中。提供表值函数以允许消费者系统地访问更改数据。

Temporal Tables

从 SQLServer 2016 开始,您可以使用系统版本化的时态表,这是一种用户表,旨在保留数据更改的完整历史记录并允许轻松进行时间点分析。这种类型的时态表被称为系统版本时态表,因为每行的有效期由系统(即数据库引擎)管理。 每个时态表都有两个明确定义的列,每个列都有一个 datetime2 数据类型。这些列称为周期列。这些期限列由系统专门用于记录每行修改时的有效期限。

例子:

CREATE TABLE dbo.test
(
   [ID] int NOT NULL PRIMARY KEY CLUSTERED
   ,[ValidFrom] datetime2 GENERATED ALWAYS AS ROW START
   ,[ValidTo] datetime2 GENERATED ALWAYS AS ROW END
   ,PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo))
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.TestHistory));

Triggers

创建 DML、DDL 或登录触发器。触发器是一种特殊类型的存储过程,当数据库服务器中发生事件时会自动运行。当用户尝试通过数据操作语言 (DML) 事件修改数据时,DML 触发器就会运行。 DML 事件是表或视图上的 INSERT、UPDATE 或 DELETE 语句。这些触发器在任何有效事件触发时触发,无论表行是否受到影响。

【讨论】:

    猜你喜欢
    • 2021-09-05
    • 1970-01-01
    • 2011-12-02
    • 1970-01-01
    • 2016-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多