在不使用触发器的情况下创建历史记录表

时间:2018-07-11 21:40:05

标签: sql-server tsql

我有一个具有25列的3000条记录的表A。我想要一个称为表A历史的历史表,其中包含所有更改的更新和删除,以便我随时查看。我通常使用游标。现在考虑使用没有被要求的触发器。你有什么其他的建议?非常感谢!

2 个答案:

答案 0 :(得分:0)

如果您使用的是tsql / SQL Server,并且不能使用触发器(这是获取所有更改的唯一肯定的方法),则可以使用在作业中安排的存储过程在每x倍的时间内运行一次,该存储过程在两个表中使用MERGE语句来获取新记录或更改。如果您需要毫无疑问地进行每一个更改,我都不建议这样做。

CREATE TABLE dbo.TableA (id INT, Column1 nvarchar(30))
CREATE TABLE dbo.TableA_History (id INT, Column1 nvarchar(30), TimeStamp DateTime)

(此代码不是生产性的,只是一般性的想法) 将以下代码放入存储过程中,并使用带有计划的Sql Server Job。

MERGE INTO dbo.TableA_History
USING dbo.TableA
ON TableA_History.id = TableA.id AND TableA_History.Column1 = TableA.Column1
WHEN NOT MATCHED BY TARGET THEN
INSERT (id,Column1,TimeStamp) VALUES (TableA.id,TableA.Column1,GETDATE())

因此,基本上,如果记录不存在或不匹配(意味着列已更改),请将记录插入历史记录表。

答案 1 :(得分:0)

即使您未使用SQL Server 2016并且系统版本表不可用,在某些情况下也可以创建不带触发器的历史记录。

在某些情况下,当您确定确定哪些例程正在修改表时,可以使用endpoint mysql:Client testDB1 { host: "localhost", port: 3306, name: "customerdb", username: "root", password: "root", poolOptions: { maximumPoolSize: 5, isXA:true }, dbOptions: { useSSL: false } }; endpoint mysql:Client testDB2 { host: "localhost", port: 3306, name: "salarydb", username: "root", password: "root", poolOptions: { maximumPoolSize: 5, isXA:true }, dbOptions: { useSSL: false } }; transaction with retries = 3, oncommit = onCommitFunction, onabort = onAbortFunction { var retWithKey = testDB1->updateWithGeneratedKeys("INSERT INTO CUSTOMER(NAME) VALUES ('Anne')", ()); string generatedKey; match retWithKey { (int, string[]) y => { var (count, ids) = y; generatedKey = ids[0]; io:println("Inserted row count: " + count); io:println("Generated key: " + generatedKey); } error err => io:println("Insert to customer table failed: " + err.message); } ret = <int>generatedKey; int key = -1; match ret { int retInt => key = retInt; error err => io:println("Converting key to string failed: " + err.message); } io:println("Generated key for the inserted row: " + key); ret = testDB2->update("INSERT INTO SALARY (ID, VALUE) VALUES (?, ?)", key, 2500); handleUpdate(ret, "Insert to SALARY table"); } onretry { io:println("Retrying transaction"); } clause创建历史记录。

例如

OUTPUT INTO

在例程中,当您使用INSERT INTO [dbo].[MainTable] OUTPUT inserted.[] ,... ,'I' ,GETUTCDATE() ,@CurrentUserID INTO [dbo].[HistoryTable] SELECT * FROM ... ; 时,我喜欢我们可以使用MERGE

  

仅可用于MERGE语句。指定类型的列   返回MERGE语句中OUTPUT子句中的nvarchar(10)   每行三个值之一:“ INSERT”,“ UPDATE”或“ DELETE”,   根据对该行执行的操作。

我们可以方便地添加$action来修改表。使用触发器时,您需要使用会话上下文或会话变量来传递user。在版本控制表中,您需要在主表中添加其他列,以便登录用户,因为它仅记录当前表的列(至少现在是这样)。

因此,基本上,这取决于您的数据和应用程序。如果表上有许多CRUD源,则触发是最安全的方法。如果您的表很大且使用率很高,那么使用user是不好的,因为它会导致阻塞和损害性能。

在我们的数据库中,我们根据情况使用所有方法:

  • 触发传统
  • 用于新开发的系统版本
  • 在历史记录中直接输出,当确保仅通过给定的例程集修改数据时