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
时,所操作的数据将插入第二个表auditmattudit
扳机一定失灵了,我不知道为什么;证据表明,尽管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
将包含更新前的记录。这是真的,但他希望每次插入时都进行审核,更新或删除,因此在插入和删除的情况下,他的审核将失败。