我不知道这些要求是否标准,但我想知道是否有解决办法可以做到以下几点:
我宁愿不必为每个表编写代码.我想知道是否有一个解决方案,您可以安装在ms-sql之上,这将为您做到这一点?
Vla*_*cea 10
假设我们有一个Book表,其审计日志信息必须存储在一个BookAuditLog表中,如下面的类图所示:
该BookAuditLog表是这样创建的:
CREATE TABLE BookAuditLog (
BookId bigint NOT NULL,
OldRowData nvarchar(1000) CHECK(ISJSON(OldRowData) = 1),
NewRowData nvarchar(1000) CHECK(ISJSON(NewRowData) = 1),
DmlType varchar(10) NOT NULL CHECK (DmlType IN ('INSERT', 'UPDATE', 'DELETE')),
DmlTimestamp datetime NOT NULL,
DmlCreatedBy varchar(255) NOT NULL,
TrxTimestamp datetime NOT NULL,
PRIMARY KEY (BookId, DmlType, DmlTimestamp)
)
Run Code Online (Sandbox Code Playgroud)
该BookAuditLog表中的列存储以下数据:
BookId列存储Book为其创建此日志事件的关联行的标识符。OldRowData存储的JSON表示Book之前执行的INSERT,更新或删除语句记录状态。NewRowData商店的JSON表示Book记录状态的INSERT,UPDATE或DELETE语句后执行。DmlType是一个枚举列,其存储创建,更新或删除一个给定的DML语句类型Book一行。DmlTimestamp存储DML语句的执行时间戳。DmlCreatedBy卖场谁发出的INSERT,UPDATE或DELETE DML语句的用户。TrxTimestamp商店改变了交易的时间戳Book记录。为了捕获 INSERT、UPDATE 和 DELETE DML 语句,我们需要创建三个数据库触发器,它们将在BookAuditLog表中插入记录。
为了拦截表上的 INSERT 语句Book,我们将创建TR_Book_Insert_AuditLog触发器:
CREATE TRIGGER TR_Book_Insert_AuditLog ON Book
FOR INSERT AS
BEGIN
DECLARE @loggedUser varchar(255)
SELECT @loggedUser = CAST(SESSION_CONTEXT(N'loggedUser') AS varchar(255))
DECLARE @transactionTimestamp datetime = SYSUTCdatetime()
INSERT INTO BookAuditLog (
BookId,
OldRowData,
NewRowData,
DmlType,
DmlTimestamp,
DmlCreatedBy,
TrxTimestamp
)
VALUES(
(SELECT id FROM Inserted),
null,
(SELECT * FROM Inserted FOR JSON PATH, WITHOUT_ARRAY_WRAPPER),
'INSERT',
CURRENT_TIMESTAMP,
@loggedUser,
@transactionTimestamp
);
END
Run Code Online (Sandbox Code Playgroud)
为了捕获Book记录上的 UPDATE 语句,我们将创建以下TR_Book_Update_AuditLog触发器:
CREATE TRIGGER TR_Book_Update_AuditLog ON Book
FOR UPDATE AS
BEGIN
DECLARE @loggedUser varchar(255)
SELECT @loggedUser = CAST(SESSION_CONTEXT(N'loggedUser') AS varchar(255))
DECLARE @transactionTimestamp datetime = SYSUTCdatetime()
INSERT INTO BookAuditLog (
BookId,
OldRowData,
NewRowData,
DmlType,
DmlTimestamp,
DmlCreatedBy,
TrxTimestamp
)
VALUES(
(SELECT id FROM Inserted),
(SELECT * FROM Deleted FOR JSON PATH, WITHOUT_ARRAY_WRAPPER),
(SELECT * FROM Inserted FOR JSON PATH, WITHOUT_ARRAY_WRAPPER),
'UPDATE',
CURRENT_TIMESTAMP,
@loggedUser,
@transactionTimestamp
);
END
Run Code Online (Sandbox Code Playgroud)
为了拦截Book表行上的 DELETE 语句,我们将创建以下TR_Book_Delete_AuditLog触发器:
CREATE TRIGGER TR_Book_Delete_AuditLog ON Book
FOR DELETE AS
BEGIN
DECLARE @loggedUser varchar(255)
SELECT @loggedUser = CAST(SESSION_CONTEXT(N'loggedUser') AS varchar(255))
DECLARE @transactionTimestamp datetime = SYSUTCdatetime()
INSERT INTO BookAuditLog (
BookId,
OldRowData,
NewRowData,
DmlType,
DmlTimestamp,
DmlCreatedBy,
TrxTimestamp
)
VALUES(
(SELECT id FROM Deleted),
(SELECT * FROM Deleted FOR JSON PATH, WITHOUT_ARRAY_WRAPPER),
null,
'DELETE',
CURRENT_TIMESTAMP,
@loggedUser,
@transactionTimestamp
);
END
Run Code Online (Sandbox Code Playgroud)
在表上执行 INSERT 语句时Book:
INSERT INTO Book (
Author,
PriceInCents,
Publisher,
Title,
Id
)
VALUES (
'Vlad Mihalcea',
3990,
'Amazon',
'High-Performance Java Persistence 1st edition',
1
)
Run Code Online (Sandbox Code Playgroud)
我们可以看到在BookAuditLog捕获刚刚在Book表上执行的INSERT语句的记录中插入了一条记录:
| BookId | OldRowData | NewRowData | DmlType | DmlTimestamp | DmlCreatedBy | TrxTimestamp |
|--------|------------|------------------------------------------------------------------------------------------------------------------------------------|---------|-------------------------|---------------|-------------------------|
| 1 | | {"Id":1,"Author":"Vlad Mihalcea","PriceInCents":3990,"Publisher":"Amazon","Title":"High-Performance Java Persistence 1st edition"} | INSERT | 2020-11-08 08:40:28.343 | Vlad Mihalcea | 2020-11-08 06:40:28.347 |
Run Code Online (Sandbox Code Playgroud)
更新Book表格行时:
UPDATE Book
SET PriceInCents = 4499
WHERE Id = 1
Run Code Online (Sandbox Code Playgroud)
我们可以看到,表BookAuditLog上的 AFTER UPDATE 触发器将添加一条新记录Book:
| BookId | OldRowData | NewRowData | DmlType | DmlTimestamp | DmlCreatedBy | TrxTimestamp |
|--------|------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------|---------|-------------------------|---------------|-------------------------|
| 1 | | {"Id":1,"Author":"Vlad Mihalcea","PriceInCents":3990,"Publisher":"Amazon","Title":"High-Performance Java Persistence 1st edition"} | INSERT | 2020-11-08 08:40:28.343 | Vlad Mihalcea | 2020-11-08 06:40:28.347 |
| 1 | {"Id":1,"Author":"Vlad Mihalcea","PriceInCents":3990,"Publisher":"Amazon","Title":"High-Performance Java Persistence 1st edition"} | {"Id":1,"Author":"Vlad Mihalcea","PriceInCents":4499,"Publisher":"Amazon","Title":"High-Performance Java Persistence 1st edition"} | UPDATE | 2020-11-08 08:43:22.803 | Vlad Mihalcea | 2020-11-08 06:43:22.807 |
Run Code Online (Sandbox Code Playgroud)
删除Book表格行时:
DELETE FROM Book
WHERE Id = 1
Run Code Online (Sandbox Code Playgroud)
BookAuditLogAFTER DELETE 触发器将一条新记录添加到Book表中:
| BookId | OldRowData | NewRowData | DmlType | DmlTimestamp | DmlCreatedBy | TrxTimestamp |
|--------|------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------|---------|-------------------------|---------------|-------------------------|
| 1 | | {"Id":1,"Author":"Vlad Mihalcea","PriceInCents":3990,"Publisher":"Amazon","Title":"High-Performance Java Persistence 1st edition"} | INSERT | 2020-11-08 08:40:28.343 | Vlad Mihalcea | 2020-11-08 06:40:28.347 |
| 1 | {"Id":1,"Author":"Vlad Mihalcea","PriceInCents":3990,"Publisher":"Amazon","Title":"High-Performance Java Persistence 1st edition"} | {"Id":1,"Author":"Vlad Mihalcea","PriceInCents":4499,"Publisher":"Amazon","Title":"High-Performance Java Persistence 1st edition"} | UPDATE | 2020-11-08 08:43:22.803 | Vlad Mihalcea | 2020-11-08 06:43:22.807 |
| 1 | {"Id":1,"Author":"Vlad Mihalcea","PriceInCents":4499,"Publisher":"Amazon","Title":"High-Performance Java Persistence 1st edition"} | | DELETE | 2020-11-08 08:44:25.630 | Vlad Mihalcea | 2020-11-08 06:44:25.633 |
Run Code Online (Sandbox Code Playgroud)
我创建了触发器来为XML做这种方式我们可以将所有表记录到同一个表中,使其更灵活
CREATE TABLE [dbo].[AuditAll] (
AuditId int NOT NULL IDENTITY(1,1),
[DateTime] datetime NOT NULL,
TableName nvarchar(255) NOT NULL,
AuditEntry xml NULL,
CONSTRAINT [PK_AuditAll] PRIMARY KEY CLUSTERED ( AuditId ASC )
)
Run Code Online (Sandbox Code Playgroud)
我只需要'旧'值,所以我只存储删除表,无论如何都可以在表中看到插入表.
CREATE TRIGGER AuditSimple
ON Simple
AFTER INSERT,DELETE,UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
IF (SELECT COUNT(*) FROM deleted) > 0
begin
Declare @AuditMessage XML
--set valut to all xml from deleted table
set @AuditMessage = (select * from deleted for xml auto)
insert into AuditAll( DateTime, TableName, AuditEntry )
values ( GetDate(), 'Simple', @AuditMessage )
end
END
GO
Run Code Online (Sandbox Code Playgroud)
我想这可以很容易地在sp_foreach中调用,为数据库中的每个表创建它,但我们现在不需要它,只记得更改你的表名
干杯
小智 5
您可以尝试基于第三方点击触发器的解决方案,例如ApexSQL Audit - 一种用于SQL Server数据库的审计工具,它捕获数据库上发生的数据更改,包括有关更改者的信息,哪些对象是影响,制作时,以及用于进行更改的SQL登录,应用程序和主机的信息.它将所有捕获的信息存储在中央存储库中,并以打印友好格式导出
免责声明:我在ApexSQL担任产品支持工程师
| 归档时间: |
|
| 查看次数: |
88197 次 |
| 最近记录: |