Tsql 用于填充审核表的基本T-SQL触发器

Tsql 用于填充审核表的基本T-SQL触发器,tsql,database-trigger,audit-tables,Tsql,Database Trigger,Audit Tables,读了这篇文章后,我建立了两张表和一个触发器。其思想是,当在第一个表Matt上执行INSERT、UPDATE或DELETE时,所操作的数据将插入第二个表auditmattudit 扳机一定失灵了,我不知道为什么;证据表明,尽管CREATE TRIGGER和随后的ALTER TRIGGER语句成功完成,审计表中没有任何条目 主表Matt: CREATE TABLE [dbo].[Matt]( [MattID] [int] IDENTITY(1,1) NOT NULL, [Text]

读了这篇文章后,我建立了两张表和一个触发器。其思想是,当在第一个表
Matt
上执行
INSERT
UPDATE
DELETE
时,所操作的数据将插入第二个表audit
mattudit

扳机一定失灵了,我不知道为什么;证据表明,尽管
CREATE TRIGGER
和随后的
ALTER TRIGGER
语句成功完成,审计表中没有任何条目

主表
Matt

CREATE TABLE [dbo].[Matt](
    [MattID] [int] IDENTITY(1,1) NOT NULL,
    [Text] [nchar](10) NULL,
 CONSTRAINT [PK_Matt] PRIMARY KEY CLUSTERED 
(
    [MattID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
审核表
mattudit

CREATE TABLE [dbo].[MattAudit](
    [MattAuditID] [int] IDENTITY(1,1) NOT NULL,
    [MattID] [int] NOT NULL,
    [Text] [nchar](10) NULL,
    [Action] [int] NOT NULL,
    [InsertedDate] [datetime] NOT NULL,
 CONSTRAINT [PK_MattAudit] PRIMARY KEY CLUSTERED 
(
    [MattAuditID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
在马特身上触发:

ALTER TRIGGER TrgMattAudit ON Matt
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;

    INSERT INTO [dbo].[MattAudit]
        ( MattID, [Text], [Action], InsertedDate )
    SELECT
        ISNULL(i.MattID, d.MattID) as MattID,
        ISNULL(i.Text, d.Text) as Text,
        CASE ISNULL(i.MattID,0) WHEN 0 THEN 0 ELSE 1 END
        +
        CASE ISNULL(d.MattID,0) WHEN 0 THEN 0 ELSE -1 END
        as [Action],
        GETDATE() as InsertedDate
    FROM
        inserted i
        INNER JOIN deleted d ON i.MattID = d.MattID;

END
下面的insert语句将在
Matt
表中插入行,但
mattudit
表中不会显示任何内容

INSERT INTO Matt ([Text]) VALUES ('Test4')

我在触发器中遗漏了什么或出错了什么?

我认为问题在于:

FROM
    inserted i
    INNER JOIN deleted d ON i.MattID = d.MattID;
  • 插入时,您仅在插入的
    中有记录
  • 删除记录时,只有
    中的记录已删除
  • 更新记录时,您将在插入的
    (新值)和删除的
    (旧值)中都有记录
如果将这两行合并,则
插入
删除
的行数始终为0行,因为在执行插入操作时,插入的
中将有1行或多行
,但删除的
中将有0行。对于
DELETE
语句,反之亦然

我的一个建议是,针对每种情况将单个触发器拆分为一个触发器(
INSERT
UPDATE
DELETE
),并在每个新触发器中使用一个查询

需要注意的是,更新后的
触发器将在
插入的
删除的
表中添加行


运行更新查询之前,
INSERTED
中的值将是放置到位的值,
DELETED
中的值将是旧值。

我认为您在那里所做的错误是在插入表和删除表之间进行内部联接。As在两个表中的MattId不应相同。我的意思是,你应该做像左或右这样的外部连接(或者在2个不同的选择中加载变量,而不是1个)。试试看,希望你能理解我

对审计表使用触发器可能不是最好的主意。SQL Server中有一些内置工具,如捕获数据更改或时态表,可以为您提供更好的解决方案。@Zoharped时态表也适用于删除的行?是的。时态表(又称系统版本表)是在SQL Server 2016中引入的—其思想是您有一个存储当前数据的表,一个存储该数据历史记录的表-它们自动链接-主表中的任何更改都将导致当前行自动推送到历史记录表-包括更新和删除。如果您使用的是较旧的版本,那么可以将变更数据捕获(2008年IIRC就提供了)放在一边:作为一项规则,应该将日志触发器设置为上次使用时触发。在日志记录操作中,验证触发器可能回滚没有意义。更新记录时,
插入的
删除的
表都将包含这些记录-
插入的
将包含更新后的记录,
删除的
将包含更新前的记录。此外,
union all
运算符将对select语句起作用,但对insert语句不起作用。此外,即使update语句将行中的值更新为已存在的相同值,也会触发更新后触发器。假设您的
Text
列在id为1的行中包含
Matt
,并且您运行
update Matt set Text='Matt',其中id=1
-该update语句仍将触发update触发器。我看到您已编辑了答案,但在大多数情况下仍然是错误的。。。“我完全同意这不应该在一次触发中处理,尽管如此。”佐哈珀莱德说,“我已经把它删减了。我将继续清理注释,因为不需要它们。当最后一条注释消失时,这条注释也将消失。“插入或更新时,您只插入了记录。”应为“插入时,您只插入了记录”。此外,“连接两条注释将始终导致0行”应为“连接两条注释将导致插入或删除0行”…当您更新记录时,
inserted
deleted
表都将包含这些记录-
inserted
将包含更新后的记录,
deleted
将包含更新前的记录。这是真的,但他希望每次插入时都进行审核,更新或删除,因此在插入和删除的情况下,他的审核将失败。