简体   繁体   English

对非特定行,列或表的更新,插入,删除操作的SQL触发器

[英]SQL Trigger on Update, Insert, Delete on non-specific row, column, or table

I have several databases that are used by several applications (one of which is our own, the others we have no control over in what they do). 我有多个数据库,供多个应用程序使用(其中一个数据库是我们自己的,其他数据库则无法控制它们的工作)。

Out software has to know when the database has last been changed. Out软件必须知道数据库的最新更改时间。 For reasons I won't get into to keep this short we decided that going with a new table per database that has a singular field: last_changed_on that has a GetDate() as a value. 由于种种原因,我不愿last_changed_on ,因此,我们决定对每个数据库使用一个具有单个字段的新表: last_changed_on ,该表的一个GetDate()作为值。 This way our own software can check when it was last changed and check it to the date it has stored for said database and do things if the date is newer than what is stored in-memory. 这样,我们自己的软件可以检查上次更改的时间,并将其检查到该数据库的存储日期,如果该日期比内存中存储的日期新,则可以执行该操作。

After doing some research we decided that working with Triggers was the way to go, but from what I could find online, triggers look at specific columns that you set for Updates. 经过研究后,我们认为使用触发器是必经之路,但是从我网上可以找到的内容来看,触发器会查看您为更新设置的特定列。

What I'd like to know is if there is a way to automate the process or just have a trigger that happens whenever anything happens insert, update, remove wise? 我想知道的是,是否有一种方法可以自动执行该过程,或者仅在发生任何事情时才触发,明智地插入,更新或删除触发器?

So I am looking for something like this: 所以我正在寻找这样的事情:

CREATE TRIGGER LastModifiedTrigger
ON [dbo].[anytable]
AFTER INSERT, UPDATE, DELETE
AS

   INSERT INTO dbo.LastModifiedTable (last_modified_on) VALUES (CURRENT_TIMESTAMP)

I know that the above example isn't a correct trigger, I'm rather new to them so I was unsure on how to word it. 我知道上面的例子不是一个正确的触发器,对他们来说我还很陌生,所以我不确定该怎么写。 It might be interesting to note that I can have my own software run several queries creating the queries automatically for each table and each column, but I'd rather avoid to do that as keeping track of all those triggers will be a pain in the long run. 可能有趣的是,我可以让自己的软件运行多个查询,从而自动为每个表和每个列创建查询,但是我宁愿避免这样做,因为长期跟踪所有这些触发器将是一件痛苦的事情。跑。 I'd prefer to have a little triggers per database as possible, if only by not having to make a trigger for each individual column name. 我希望每个数据库都尽可能少有触发器,即使不必为每个单独的列名都创建触发器。

Edit: To clarify: I am trying to avoid having to create an automated script that goes and scans every table, and sequentially every column of every table, to create a trigger to see if something is changed there. 编辑:澄清一下:我试图避免创建自动脚本来扫描每个表,然后依次扫描每个表的每个列,以创建触发器来查看是否在那里进行了更改。 My biggest issue at the moment is the trigger behavior on updates , but I'm hoping to avoid having to specify tables as well for insert and delete 目前我最大的问题是updates的触发行为,但我希望避免为insertdelete也必须指定表

Edit 2: To avoid future confusion, I'm looking for a solution to this problem for both SQL Server (MS SQL/T SQL) and MySQL 编辑2:为避免将来出现混乱,我正在寻找针对SQL Server(MS SQL / T SQL)和MySQL的此问题的解决方案

Edit 3: Turns out that I read the documentation very wrongly and (at least on MySql) the trigger activates on any given updated column without having to define a specific one. 编辑3:事实证明,我非常错误地阅读了文档,并且(至少在MySql上)触发器在任何给定的更新列上都被激活,而不必定义特定的列。 Regardless, I'm still wondering if there is a way to just have less triggers than having one for each table in a database. 无论如何,我仍然想知道是否有一种方法可以使触发器少于数据库中每个表的触发器。 (ie 1 for any type of update() , 1 for any type of insert() , and 1 for any type of delete() (即1代表任何类型的update() ,1代表任何类型的insert() ,1代表任何类型的delete()

EDIT 4: Forgot that the argument for overwriting 1 field will come with performance issues, I've considered this and I'm now working with multiple rows. 编辑4:忘记了覆盖1字段的参数将带来性能问题,我已经考虑了这一点,现在正在处理多行。 I've also handled the creating of 3 triggers ( insert() , update() , and delete() ) for each database through my software's code, I really wished this could've been avoided, but it cannot. 我还通过我的软件代码为每个数据库创建了3个触发器( insert()update()delete() ),我真希望可以避免这种情况,但事实并非如此。

Solution

After a bunch more digging on the internet and keep finding opposite results of what I was looking for, and a bunch of trial and error, I found a solution. 经过一堆互联网的探索,并不断发现与我所寻找的结果相反的结果,以及一堆反复试验之后,我找到了解决方案。 First and foremost: having triggers not being dependent on a table (aka, the trigger activates for every table is impossible, it cannot be done, which is too bad, it would've been nice to keep this out of the program code, but nothing I can do about it. 最重要的是:让触发器不依赖于表(又称为触发器,不可能为每个表激活),这是不可能完成的,这太糟糕了,将其排除在程序代码之外会很好,但是我对此无能为力。

Second: the issue for updates on not being column specific was an error due to my part for searching for triggers not being dependent on specific columns only giving me examples for triggers that are. 第二:关于不是特定于列的更新的问题是一个错误,这是由于我搜索触发器不依赖于特定列的部分仅是为我提供了触发器的示例。 The following solution works for MySql, I have yet to test this on SQL Server, but I expect it to not be too different. 以下解决方案适用于MySql,我尚未在SQL Server上对其进行测试,但我希望它不会有太大不同。

CREATE TRIGGER [tablename]_last_modified_insert
   AFTER INSERT/UPDATE/DELETE ON [db].[tablename]
     FOR EACH ROW
     BEGIN
        INSERT INTO [db].last_modified(last_modified_on)
        VALUES(current_timestamp())
     END

As for dynamically creating these triggers, the following show how I get it to work: First Query: 至于动态创建这些触发器,下面显示了如何使其工作:第一个查询:

SHOW TABLES

I run the above query to get all the tables in the database, exclude the last_modified I made myself, and loop through all of them, creating 3 triggers for each. 我运行上面的查询以获取数据库中的所有表,排除我自己做的last_modified ,并遍历所有表,为每个表创建3个触发器。

A big thank you to Arvo and T2PS for their replies, their comments helped by pointing me in the right direction and writing up the solution. 非常感谢Arvo和T2PS的答复,他们的意见为我指明了正确的方向并编写了解决方案,对他们有所帮助。

You're slightly off in the assumption that SQL Server triggers are per-column; 假设SQL Server触发器是按列的,则您略有偏离。 the CREATE TRIGGER syntax binds the trigger to the named table for the specified operations. CREATE TRIGGER语法将触发器绑定到指定操作的命名表。 The trigger will be called with two logical tables in scope ( inserted & deleted ) that contain the rows modified by the operation that caused the trigger to fire; 将使用范围内的两个逻辑表( inserteddeleted )来调用触发器,该逻辑表包含由导致触发器触发的操作所修改的行; if you wanted to check for specific columns' values or changes, then the trigger logic would need to operate against those logical tables. 如果您想检查特定列的值或更改,则触发逻辑将需要针对那些逻辑表进行操作。

If you take this approach, you will need to create a trigger for each table you wish to monitor in this fashion; 如果采用这种方法,则需要以这种方式为要监视的每个表创建一个触发器。 we've had a similar need to track changes (at a more granular level), we didn't find a "pseudotable" that corresponds to all tables in a schema/database. 我们也有类似的需求(更细粒度地)跟踪更改,我们没有找到对应于架构/数据库中所有表的“伪表”。 You should also be aware that locking semantics will come into play by doing this, as you will have triggers from multiple tables all targeting the same row for an update as part of separate operations -- depending on the concurrency model in effect, you could be looking at performance consequences by doing so if you expect multiple DML queries to operate concurrently against your database. 您还应该意识到,这样做会发挥锁定语义的作用,因为您将有多个表的触发器都针对同一行进行更新,这是单独操作的一部分-根据有效的并发模型,您可能会如果您希望多个DML查询针对您的数据库并发运行,则可以这样做来查看性能后果。

I would suggest checking Arvo's commented link above for suitability instead; 我建议改用上面的Arvo评论链接,以了解其适用性; querying system views is more likely to avoid contention (and other performance-related) issues from using triggers in your scenario. 查询系统视图更有可能避免在方案中使用触发器而引起争用(以及其他与性能相关的问题)。

After a bunch more digging on the internet and keep finding opposite results of what I was looking for, and a bunch of trial and error, I found a solution. 经过一堆互联网的探索,并不断发现与我所寻找的结果相反的结果,以及一堆反复试验之后,我找到了解决方案。 First and foremost: having triggers not being dependent on a table (aka, the trigger activates for every table is impossible, it cannot be done, which is too bad, it would've been nice to keep this out of the program code, but nothing I can do about it. 最重要的是:让触发器不依赖于表(又称为触发器,不可能为每个表激活),这是不可能完成的,这太糟糕了,将其排除在程序代码之外会很好,但是我对此无能为力。

Second: the issue for updates on not being column specific was an error due to my part for searching for triggers not being dependent on specific columns only giving me examples for triggers that are. 第二:关于不是特定于列的更新的问题是一个错误,这是由于我搜索触发器不依赖于特定列的部分仅是为我提供了触发器的示例。 The following solution works for MySQL, I have yet to test this on SQL Server, but I expect it to not be too different. 以下解决方案适用于MySQL,但我尚未在SQL Server上对其进行测试,但我希望它不会有太大不同。

CREATE TRIGGER [tablename]_last_modified_insert
   AFTER INSERT/UPDATE/DELETE ON [db].[tablename]
     FOR EACH ROW
     BEGIN
        INSERT INTO [db].last_modified(last_modified_on)
        VALUES(current_timestamp())
     END

As for dynamically creating these triggers, the following show how I get it to work: First Query: 至于动态创建这些触发器,下面显示了如何使其工作:第一个查询:

SHOW TABLES

I run the above query to get all the tables in the database, exclude the last_modified I made myself, and loop through all of them, creating 3 triggers for each. 我运行上面的查询以获取数据库中的所有表,排除我自己做的last_modified ,并遍历所有表,为每个表创建3个触发器。

Perhaps you could use Audit for SQL Server: 也许您可以使用Audit for SQL Server:

CREATE SERVER AUDIT [ServerAuditName]
TO FILE
(
   FILEPATH = N'C:\Program Files......'
)
ALTER SERVER AUDIT [ServerAuditName] WITH (STATE=ON)
GO   
CREATE DATABASE AUDIT SPECIFICATION [mySpec]
FOR SERVER AUDIT [ServerAuditName]
ADD (INSERT, UPDATE, DELETE ON DATABASE::databasename BY [public])
WITH (STATE=ON)
GO

Then you can query for changes: 然后,您可以查询更改:

SELECT * 
FROM sys.fn_get_audit_file ('C:\Program Files......',default,default);
GO  

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM