SQL Server – History Table (Audit/Archive Table)
前言
续上一篇的 Soft Delete 后, 我们继续来看看 History Table (Audit/Archive Table).
Archive Table 市场上有了这样叫, 但我觉得它比较杂, 因为它既保存了 History, 也多少记入 operation 和时间, 所以带有一点 Audit 的味道.
我们姑且叫它 HIstory Table 就好呗.
上回说到我们的需求就是不希望任何数据被删除, 找不回来.
除了 Soft Delete, Temporal Table 能完成这个需求, 还有就是 History Table.
也就就是自己做一个 table 然后把所有 delete/update 移除的数据放以 json 的方式存进去. (和 temporal 差不多, 只是 temporal 是每一个表都一个 history table, 然后它不是 json 而是完整的表结构)
这个方案的优点就是没有 Temporal 那么重, 又比 Soft Delete 轻.
Step 1: Create History Table
大概长这样

Step 2: Trigger After Delete
GO
CREATE OR ALTER TRIGGER [TR_Country_AfterDelete_ForAuditData] ON [Country]
AFTER DELETE
AS
IF (ROWCOUNT_BIG() = 0) RETURN;
SET NOCOUNT ON; DECLARE @i int = 0, @count int;
SELECT @count = COUNT(*) FROM deleted;
DECLARE @dateCreated datetimeoffset(3) = CAST(SYSDATETIMEOFFSET() AT TIME ZONE 'Singapore Standard Time' AS datetimeoffset(3)); WHILE(@i < @count)
BEGIN
INSERT INTO AuditDataLog (TableName, Operation, DeletedDataJson, InsertedDataJson, DateCreated)
VALUES (
'Country',
'Delete',
(SELECT * FROM (SELECT * FROM deleted ORDER BY CountryId OFFSET @i ROWS FETCH NEXT 1 ROWS ONLY) Temp FOR JSON AUTO, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER),
NULL,
@dateCreated
);
SET @i += 1;
END
GO
要记得哦, deleted 是一个表, 里面会有很多 deleted rows 的. 这里把 deleted row 一条一条 insert 是为了以后方便 filter 查看. 但是会让性能慢的哦.
Step 3: Trigger After Update
和上面差不多, 只是多了一句 for inserted 而已.
GO
CREATE OR ALTER TRIGGER [TR_Country_AfterDelete_ForAuditData] ON [Country]
AFTER UPDATE
AS
IF (ROWCOUNT_BIG() = 0) RETURN;
SET NOCOUNT ON; DECLARE @i int = 0, @count int;
SELECT @count = COUNT(*) FROM deleted;
DECLARE @dateCreated datetimeoffset(3) = CAST(SYSDATETIMEOFFSET() AT TIME ZONE 'Singapore Standard Time' AS datetimeoffset(3)); WHILE(@i < @count)
BEGIN
INSERT INTO AuditDataLog (TableName, Operation, DeletedDataJson, InsertedDataJson, DateCreated)
VALUES (
'Country',
'Update',
(SELECT * FROM (SELECT * FROM deleted ORDER BY CountryId OFFSET @i ROWS FETCH NEXT 1 ROWS ONLY) Temp FOR JSON AUTO, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER),
(SELECT * FROM (SELECT * FROM inserted ORDER BY CountryId OFFSET @i ROWS FETCH NEXT 1 ROWS ONLY) Temp FOR JSON AUTO, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER),
@dateCreated
);
SET @i += 1;
END
GO
题外话:
本来想把这个表叫 AuditDataLog 的, 但由于 deleted 没有办法记入 DeletedBy (除非搞一些 stored procedure)
所以还是把它定位为 History Table 就好了. 如果想知道是谁 delete 了, 那么这里获取到时间后, 在去查 Audit Api Log, 有了时间范围, 要找出谁 performance 了相关 action 就容易多了.
SQL Server – History Table (Audit/Archive Table)的更多相关文章
- SQL Server数据恢复准备之TRUNCATE TABLE理解
SQL Server数据恢复准备之TRUNCATE TABLE理解 转自:https://blog.51cto.com/aimax/2142553 易语随风去关注0人评论6717人阅读2018-07- ...
- SQL Server 查看分区表(partition table)的分区范围(partition range)
https://www.cnblogs.com/chuncn/archive/2009/02/20/1395165.html SQL Server 2005 的分区表(partition table) ...
- SQL Server 审计(Audit)
审计(Audit)用于追踪和记录SQL Server实例,或者单个数据库中发生的事件(Event),审计运作的机制是通过捕获事件(Event),把事件包含的信息写入到事件日志(Event Log)或审 ...
- 1 SQL SERVER 实现字符串分割成table的方法
CREATE FUNCTION [dbo].[fn_SplitStringToTable] ( @p_Input VARCHAR(MAX), @p_Delimeter CHAR() = ',' ) R ...
- Sql Server中的表访问方式Table Scan, Index Scan, Index Seek
1.oracle中的表访问方式 在oracle中有表访问方式的说法,访问表中的数据主要通过三种方式进行访问: 全表扫描(full table scan),直接访问数据页,查找满足条件的数据 通过row ...
- 转:Sql Server中的表访问方式Table Scan, Index Scan, Index Seek
0.参考文献 Table Scan, Index Scan, Index Seek SQL SERVER – Index Seek vs. Index Scan – Diffefence and Us ...
- P6 Professional Installation and Configuration Guide (Microsoft SQL Server Database) 16 R1
P6 Professional Installation and Configuration Guide (Microsoft SQL Server Database) 16 R1 May ...
- SQL Server表和字段说明的增加和更新
1. 增加字段说明 EXEC sp_addextendedproperty 'MS_Description', 'some description', 'user', ...
- SQL SERVER临时表的使用
SQL SERVER临时表的使用 drop table #Tmp --删除临时表#Tmpcreate table #Tmp --创建临时表#Tmp( ID int IDENTITY (1 ...
- Microsoft SQL Server Version List [sqlserver 7.0-------sql server 2016]
http://sqlserverbuilds.blogspot.jp/ What version of SQL Server do I have? This unofficial build ch ...
随机推荐
- python面向对象:继承
python面向对象:继承super()的用 super()的用法 一: class A: def __init__(self): self.a = '这是一个属性' def add(self, x) ...
- 使用 useSeoMeta 进行 SEO 配置
title: 使用 useSeoMeta 进行 SEO 配置 date: 2024/7/30 updated: 2024/7/30 author: cmdragon excerpt: 摘要:本文介绍了 ...
- Vue Hook 封装通用型表格
一.创建通用型表格的需求 实现一个通用型表格组件,具备以下功能: 动态列配置. 分页功能. 排序功能. 可扩展的行操作功能. 二.设计通用型表格组件 首先,需要设计一个基础的表格组件,它接受列配置.数 ...
- 【Maxwell】01 安装及入门
官网地址: https://maxwells-daemon.io/ 下载地址(版本发行): https://github.com/zendesk/maxwell/releases 参考教程自尚硅谷视频 ...
- 【Linux】快速文件交互 lrzsz
首先需要安装依赖: yum install -y lrzsz 没有此依赖,Linux提示找不到命令: [root@localhost ~]# rz -bash: rz: 未找到命令 [root@loc ...
- 【PostgreSQL】01 环境搭建
[PostgreSQL数据库安装] 数据库本体就没下本机了,直接挂服务器的Docker上面跑 docker pull postgres:9.4 创建容器并运行: docker run --name p ...
- 【Spring】09 后续的学习补充 vol3
原生JDBC事务: package dao; import cn.dzz.util.DruidUtil; import org.apache.commons.dbutils.QueryRunner; ...
- 系数矩阵为Hessian矩阵时使用“Pearlmutter trick”或“有限差分法”近似的共轭梯度解法 —— Hession-free的共轭梯度法
共轭梯度法已经在前文中给出介绍: python版本的"共轭梯度法"算法代码 共轭梯度法用来求解方程A*x=b,且A为正定矩阵. 在机器学习领域很多优化模型的求解最终可以写为A*x= ...
- 清除 Nuxt 状态缓存:clearNuxtState
title: 清除 Nuxt 状态缓存:clearNuxtState date: 2024/8/7 updated: 2024/8/7 author: cmdragon excerpt: 摘要:本文介 ...
- Mysql 不用Json存储 List<Long>的方式
public static void main(String[] args) { List<Long> idList = new ArrayList<>(); for (int ...