判断字段是否被更新 新旧数据写入Audit Log表中
程序员文章站
2023-12-14 19:30:58
insus.net解决这个问题,只有创建另外一个表,将存储用户决定要跟踪的表,以及这个表中需要跟踪的字段。 还要创建另外一个表[audit],就是存储跟踪记录的表: 复制代...
insus.net解决这个问题,只有创建另外一个表,将存储用户决定要跟踪的表,以及这个表中需要跟踪的字段。
还要创建另外一个表[audit],就是存储跟踪记录的表:
audit
set ansi_nulls on
go
set quoted_identifier on
go
set ansi_padding on
go
create table [dbo].[audit](
[audit_nbr] [int] identity(1,1) not null,
[audittype] [char](1) not null,
[tablename] [nvarchar](128) not null,
[fieldname] [nvarchar](128) null,
[oldvalue] [nvarchar](4000) null,
[newvalue] [nvarchar](4000) null,
[username] [nvarchar](128) null,
[createdate] [datetime] not null,
primary key clustered
(
[audit_nbr] asc
)with (pad_index = off, statistics_norecompute = off, ignore_dup_key = off, allow_row_locks = on, allow_page_locks = on) on [primary]
) on [primary]
go
set ansi_padding off
go
alter table [dbo].[audit] with check add check (([audittype]='d' or [audittype]='u' or [audittype]='i'))
go
alter table [dbo].[audit] add default (getdate()) for [createdate]
go
解决是谁更新数据,是使用这个方法:在sql触发器或存储过程中获取在程序登录的用户
接下来,为跟踪表写一个更新trigger触发器。
在触发器中访问inserted或deleted的内部临时触发表,会得一个异常invalid object name 'inserted' 或是invalid object name 'deleted' ,解决此问题,可以参考这篇:
exec(execute)函数访问inserted或deleted的内部临时触发表
下面为表更新触发器(部分),有注释:
--@n和@o两个变量,一个存储更新数据值,一个为原有数据值
declare @sql nvarchar(max),@n decimal(18,0),@o decimal(18,0)
--@i变量是用户需要跟踪的字段
set @sql = n'select @n = ['+ convert(nvarchar(max),@i) +'] from #inserted'
--执行动态sql语句。
execute sp_executesql @sql,
n'@n decimal(18,0) output',
@n output;
--下面sql代码,是从deleted表中获取原来数据值。
set @sql = n'select @o = ['+ convert(nvarchar(max),@i) +'] from #deleted'
execute sp_executesql @sql,
n'@o decimal(18,0) output',
@o output;
--对比两个数据值,更新值与原有值,如果不一样,把数据插入audit log表中。
if (isnull(@n,0) <> isnull(@o,0))
execute [dbo].[usp_audit_insert] 'u','<tablename>','<fieldname>',@o,@n,@username
上面代码还有一个存储过程,原因是如果多表或是一个表有更新或是删除需要把跟踪的数据插入audit log表中时,为了更好维护与代码冗余,因此把插入audit log表的过程,写成一个存储过程:
usp_audit_insert
set ansi_nulls on
go
set quoted_identifier on
go
alter procedure [dbo].[usp_audit_insert]
(
@audittype [char](1),
@tablename [nvarchar](128),
@fieldname [nvarchar](128),
@oldvalue [nvarchar](4000),
@newvalue [nvarchar](4000),
@username [nvarchar](128)
)
as
insert into [dbo].[audit]
([audittype],[tablename],[fieldname],[oldvalue],[newvalue],[username])
values
(@audittype,@tablename,@fieldname,@oldvalue,@newvalue,@username)
还要创建另外一个表[audit],就是存储跟踪记录的表:
复制代码 代码如下:
audit
set ansi_nulls on
go
set quoted_identifier on
go
set ansi_padding on
go
create table [dbo].[audit](
[audit_nbr] [int] identity(1,1) not null,
[audittype] [char](1) not null,
[tablename] [nvarchar](128) not null,
[fieldname] [nvarchar](128) null,
[oldvalue] [nvarchar](4000) null,
[newvalue] [nvarchar](4000) null,
[username] [nvarchar](128) null,
[createdate] [datetime] not null,
primary key clustered
(
[audit_nbr] asc
)with (pad_index = off, statistics_norecompute = off, ignore_dup_key = off, allow_row_locks = on, allow_page_locks = on) on [primary]
) on [primary]
go
set ansi_padding off
go
alter table [dbo].[audit] with check add check (([audittype]='d' or [audittype]='u' or [audittype]='i'))
go
alter table [dbo].[audit] add default (getdate()) for [createdate]
go
解决是谁更新数据,是使用这个方法:在sql触发器或存储过程中获取在程序登录的用户
接下来,为跟踪表写一个更新trigger触发器。
在触发器中访问inserted或deleted的内部临时触发表,会得一个异常invalid object name 'inserted' 或是invalid object name 'deleted' ,解决此问题,可以参考这篇:
exec(execute)函数访问inserted或deleted的内部临时触发表
下面为表更新触发器(部分),有注释:
复制代码 代码如下:
--@n和@o两个变量,一个存储更新数据值,一个为原有数据值
declare @sql nvarchar(max),@n decimal(18,0),@o decimal(18,0)
--@i变量是用户需要跟踪的字段
set @sql = n'select @n = ['+ convert(nvarchar(max),@i) +'] from #inserted'
--执行动态sql语句。
execute sp_executesql @sql,
n'@n decimal(18,0) output',
@n output;
--下面sql代码,是从deleted表中获取原来数据值。
set @sql = n'select @o = ['+ convert(nvarchar(max),@i) +'] from #deleted'
execute sp_executesql @sql,
n'@o decimal(18,0) output',
@o output;
--对比两个数据值,更新值与原有值,如果不一样,把数据插入audit log表中。
if (isnull(@n,0) <> isnull(@o,0))
execute [dbo].[usp_audit_insert] 'u','<tablename>','<fieldname>',@o,@n,@username
上面代码还有一个存储过程,原因是如果多表或是一个表有更新或是删除需要把跟踪的数据插入audit log表中时,为了更好维护与代码冗余,因此把插入audit log表的过程,写成一个存储过程:
复制代码 代码如下:
usp_audit_insert
set ansi_nulls on
go
set quoted_identifier on
go
alter procedure [dbo].[usp_audit_insert]
(
@audittype [char](1),
@tablename [nvarchar](128),
@fieldname [nvarchar](128),
@oldvalue [nvarchar](4000),
@newvalue [nvarchar](4000),
@username [nvarchar](128)
)
as
insert into [dbo].[audit]
([audittype],[tablename],[fieldname],[oldvalue],[newvalue],[username])
values
(@audittype,@tablename,@fieldname,@oldvalue,@newvalue,@username)