创建用于插入、修改和删除的数据库触发器的正确​​语法是什么

2024-05-09

我有一个看起来像是 SQL Server 中数据库触发器的基本场景,但我遇到了一个问题。

我有桌子Users(身份证、姓名、电话等)我有桌子用户历史记录(id、user_id 操作、字段、时间戳)

我想要一个数据库触发器,可以随时插入、更新或删除用户,我想要在 UsersHistory 中创建一条新记录,其中包含用户 ID 和已完成的操作(插入新的、更新的字段、删除的 ID)。基本上是一个审核日志表。

这就是我走了多远,但我不知道如何:

  1. 获取修改和删除的id
  2. 如何获取已更改的字段列表以及已提交的操作(插入、删除、更新)

CREATE TRIGGER Update_Users_History 
   ON  Users
   AFTER INSERT,DELETE,UPDATE
 AS 
 BEGIN
-- Insert statements for trigger here

insert into UsersHistory (user_id, [action], [fields], timestamp)
select  max(id) as user_id, {action ??},{fields??}  getdate() from Users)

END
GO

有什么建议么?


最简单的可能是简单地创建三个触发器 - 每个操作一个:

CREATE TRIGGER trgUserInsert
ON dbo.User AFTER INSERT
AS BEGIN
   INSERT INTO dbo.UserHistory............
END     

CREATE TRIGGER trgUserDelete
ON dbo.User AFTER DELETE
AS BEGIN
   INSERT INTO dbo.UserHistory............
END 

CREATE TRIGGER trgUserUpdate
ON dbo.User AFTER UPDATE
AS BEGIN
   INSERT INTO dbo.UserHistory............
END 

这样,事情就很简单,您很容易理解自己在做什么,此外,它还使您能够关闭单个操作的触发器,例如,如果您需要插入或删除大量项目。

在触发器内部,您有两个“伪表” -Inserted(用于插入和更新)和Deleted(用于更新和删除)。这些伪表包含新插入的值(或 UPDATE 中更新的值),或已删除(对于 DELETE)或已更新的值(更新之前的旧值,对于 UPDATE 操作)。

您需要注意,即使您更新大量行,例如,触发器也会被调用一次。Inserted and Deleted通常包含多行。

作为示例,您可以编写一个像这样的“AFTER INSERT”触发器(只是猜测您的表结构可能是什么......):

CREATE TRIGGER trgUserInsert
ON dbo.User AFTER INSERT
AS BEGIN
   INSERT INTO 
      dbo.UserHistory(UserID, Action, DateTimeStamp, AuditMessage)
      SELECT 
         i.UserID, 'INSERT', getdate(), 'User inserted into table'
      FROM
         Inserted i
END     

您正在寻找一种方法来找出该触发器引起的“操作”?我没有看到任何方法可以做到这一点 - 将三个触发器分开的另一个原因。找到这个问题的唯一方法是计算Inserted and Updated tables:

  • 如果两个计数都大于零,则为UPDATE
  • if the Inserted表有行,但是Deleted不,这是一个INSERT
  • if the Inserted表没有行,但是Deleted确实,这是一个DELETE

您还在寻找“已更新的字段列表”-同样,您实际上不会有任何简单的解决方案。您可以只循环浏览“用户”表中感兴趣的字段,然后检查

IF UPDATE(fieldname) ......

但这有点乏味。

或者你可以使用COLUMNS_UPDATED() http://msdn.microsoft.com/en-us/library/ms186329.aspx函数 - 然而,这并没有给你一个很好的列名列表,而是一个 VARBINARY,其中每一列基本上都是一位,如果它打开,该列就会被更新。不太好用......


如果您确实想创建一个大触发器,这可以作为基础 - 它会检测导致触发器触发的操作,并将条目插入到您的 User_History 表中:

CREATE TRIGGER trgUser_Universal
ON dbo.Users
AFTER INSERT, UPDATE, DELETE
AS BEGIN
  DECLARE @InsHasRows BIT = 0
  DECLARE @DelHasRows BIT = 0

  IF EXISTS(SELECT TOP 1 * FROM INSERTED)
    SET @InsHasRows = 1

  IF EXISTS(SELECT TOP 1 * FROM DELETED)
    SET @DelHasRows = 1

  DECLARE @TriggerAction VARCHAR(20)

  IF @InsHasRows = 1 AND @DelHasRows = 1 
     SET @TriggerAction = 'UPDATE'
  ELSE
     IF @InsHasRows = 1
        SET @TriggerAction = 'INSERT'
     ELSE  
        SET @TriggerAction = 'DELETE'

  IF @InsHasRows = 1
    INSERT INTO dbo.UsersHistory(user_id, [action], [fields], timestamp)
      SELECT i.UserId, @TriggerAction, null, getdate()
      FROM INSERTED i
  ELSE  
    INSERT INTO dbo.UsersHistory(user_id, [action], [fields], timestamp)
      SELECT d.UserId, @TriggerAction, null, getdate()
      FROM DELETED d
END

我还没有包含确定哪些字段已更新的部分 - 这是留给读者的练习:-)


这些帮助有用?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

创建用于插入、修改和删除的数据库触发器的正确​​语法是什么 的相关文章

  • 数据库设计:类别在自己的表中?

    我正在将几个数据库重新设计成一个综合数据库 并且我注意到旧数据库的先前设计者喜欢将类别存储在自己的表中 例如 假设有一个表boats bid integer bname string color integer 并且在应用程序中有一个下拉框
  • SQL 更新数据集中的位置

    id1 id2 bool 1 1 F 1 2 F 2 1 F UPDATE table name SET bool T WHERE id1 id2 IN 1 1 2 1 Need work here 所以基本上我想选择条件为 id1 id2
  • 仅从数据库获取我想要的数据但保留结构

    我正在尝试在 powerbi 上执行此操作 但我想这只是基本的 SQL 我想将我的数据导入到 powerBi 中 但使用一些 id 对其进行过滤 我们以这个例子为例 我与一些公司有数据库 表1 每个公司都有建筑物 表2 每个建筑物有员工 表
  • 删除原始数据中部分重复的记录

    我需要删除表中时间间隔为 1 或 2 分钟或相同且必须相同的所有记录ID但保留第一个记录 ID Time SN SD WE FW 10 2014 06 30 19 17 37 000 I 0 100 0 10 2014 06 30 19 1
  • 混合语言源目录布局

    我们正在运行一个使用多种不同语言的大型项目 Java Python PHP SQL 和 Perl 到目前为止 人们一直在自己的私有存储库中工作 但现在我们希望将整个项目合并到一个存储库中 现在的问题是 目录结构应该是什么样的 我们应该为每种
  • 如何在没有 EF 的 ASP.NET MVC 中使用普通 sql?

    我有一个使用 linq to sql 的类 如何在 ASP NET MVC 3 中使用普通 sql 而不使用 EF 来实现相同的功能 public ActionResult Index var List from c in db OFFIC
  • 按小时拆分日期/时间数据并将日期/时间范围展开为行

    我正在尝试使用 SQL Server 将一系列日期 时间数据扩展为多行 例如 我的数据看起来像 Date StartTime EndTime EmployeeID ShiftType 10 1 2019 8 30 00AM 4 57 00P
  • 从数据库而不是配置文件中读取 CodeIgniter 配置值

    您可能知道 当您使用 CI 创建新项目时 您必须手动输入基本网址 加密密钥在config config php中 我正在努力克服这个问题 因此正在寻找一种方法read那些价值观而是从数据库中 为客户进行安装并设置时间作为一个整体decrea
  • 清除表中的所有行将身份规范重置为零并且不影响外键?

    我们已经创建了数据库框架以及所有关系和依赖关系 但表内部只是虚拟数据 我们需要删除这些虚拟数据 并开始添加正确的数据 我们怎样才能清除所有内容并将主键 IsIdentity 是 保留为零 并且不影响外部表关系结构 多谢 您可以采取以下步骤
  • WooCommerce:在数据库中查找产品

    我正在使用 WooCommerce 创建一个网站 我想根据用户在主页搜索表单中输入的邮政编码来限制用户可用的产品 为了能够实现这一目标 我必须在 phpMyAdmin 的数据库中指定每个产品的条件 但我似乎找不到它 有谁知道 phpmyAd
  • MySQL:你能指定一个随机限制吗?

    有没有办法在 SQL MySQL 中随机化限制数字 我希望能够做的是在查询中获取随机数量的结果以在插入子查询中使用 而无需任何服务器端脚本 我希望能够作为假设说明运行的查询是 SELECT id FROM users ORDER BY RA
  • 返回行位置 - Postgres

    我返回一个带有位置的表 select from select row number over as position from organization result where data1 Hello 返回这个 这是正确的 data1 H
  • 是否可以自动化 SQL Server 2008 分析器?

    有一个post https stackoverflow com questions 488020 what is your most useful sql trick to avoid writing more code关于有用的 SQL
  • t sql中的相对路径?

    如何获取t sql中的相对路径 举个例子 sql文件位于文件夹中D temp 我想获取文件夹中文件hello txt的路径D temp App Data 如何使用相对路径引用 假设我正在 SQL Server Management Stud
  • ASP.NET 网站上的 XSS 攻击 [已关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我遇到了很大的麻烦 请帮忙 我的网站
  • 获取查询的行号

    我有一个查询将返回一行 当表排序时 有什么方法可以找到我正在查询的行的行索引吗 我试过了rowid但当我期待第 7 行时却得到了 582 Eg CategoryID Name I9GDS720K4 CatA LPQTOR25XR CatB
  • 具有 LINQ 支持的最完整的 ORM?

    我正在寻找一个提供完整或接近完整的 LINQ 支持的 ORM LINQ 到 SQL 支持 LINQ 内部的所有内容 Contains Math Log 等 在不创建新数据上下文的情况下无法预先加载关系属性 ADO NET 实体框架 糟糕的
  • MySQL 触发器和 SUM()

    我有两张桌子 学生桌和家庭桌 在学生中 我有列 st venue 和total venue 家里我有收入 Total Revenue 是学生 st 收入与家庭收入之和 其中 family id student student id stud
  • sql server GO 相当于 oracle

    我正在为 Oracle 编写迁移脚本 我需要更改表结构 然后用数据填充它 我想先进行结构更改 然后再进行数据更改 在 SQL Server 中我会使用GO分离批次 是否有 SQL ServerGOOracle 中的等效命令 It s and
  • 如何打印Oracle中过程的定义?

    oracle中有没有办法查看过程的结构是什么 我正在尝试记录并运行程序 并希望将实际的程序结构存储在我的日志中 您可以查询ALL SOURCE table SELECT text FROM all source WHERE owner lt

随机推荐