我找不到一种简单/通用的方法来注册审计表,在某些表上更改了列。
我试图以这种方式在更新后使用触发器来执行此操作:
首先是审计表定义:
CREATE TABLE [Audit](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Date] [datetime] NOT NULL default GETDATE(),
[IdTypeAudit] [int] NOT NULL, --2 for Modify
[UserName] [varchar](50) NULL,
[TableName] [varchar](50) NOT NULL,
[ColumnName] [varchar](50) NULL,
[OldData] [varchar](50) NULL,
[NewData] [varchar](50) NULL )
接下来在任何表中的AFTER UPDATE触发器:
DECLARE
@sql varchar(8000),
@col int,
@colcount int
select @colcount = count(*) from INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'MyTable'
set @col = 1
while(@col < @colcount )
begin
set @sql=
'INSERT INTO Audit
SELECT 2, UserNameLastModif, ''MyTable'', COL_NAME(Object_id(''MyTable''), '+ convert(varchar,@col) +'), Deleted.'
+ COL_NAME(Object_id('MyTable'), @col) + ', Inserted.' + COL_NAME(Object_id('MyTable'), @col) + '
FROM Inserted LEFT JOIN Deleted ON Inserted.[MyTableId] = Deleted.[MyTableId]
WHERE COALESCE(Deleted.' + COL_NAME(Object_id('MyTable'), @col) + ', '''') <> COALESCE(Inserted.' + COL_NAME(Object_id('MyTable'), @col) + ', '''')'
--UserNameLastModif is an optional column on MyTable
exec(@sql)
set @col = @col + 1
end
问题
我一直在为网络寻找解决方案,但我不知道
任何想法?
谢谢!
答案 0 :(得分:1)
这凸显了结构选择的更大问题。尝试编写基于集合的解决方案。删除循环和动态SQL并编写插入审计行的单个语句。这是可能的,但是可以更容易地考虑不同的表格布局,例如将所有列保留在1行而不是分割它们。
在SQL 2000中使用syscolumns。在SQL 2005+中使用sys.columns。即。
SELECT column_id FROM sys.columns WHERE object_id = OBJECT_ID(DB_NAME()+'.dbo.Table');
答案 1 :(得分:1)
@Santiago:如果您仍想在动态SQL中编写它,则应首先准备所有语句然后执行它们。 对于所有语句,8000个字符可能不够。一个好的解决方案是使用表来存储它们。
IF NOT OBJECT_ID('tempdb..#stmt') IS NULL
DROP TABLE #stmt;
CREATE TABLE #stmt (ID int NOT NULL IDENTITY(1,1), SQL varchar(8000) NOT NULL);
然后将行exec(@sql)
替换为INSERT INTO #stmt (SQL) VALUES (@sql);
然后执行每一行。
WHILE EXISTS (SELECT TOP 1 * FROM #stmt)
BEGIN
BEGIN TRANSACTION;
EXEC (SELECT TOP 1 SQL FROM #stmt ORDER BY ID);
DELETE FROM #stmt WHERE ID = (SELECT MIN(ID) FROM #stmt);
COMMIT TRANSACTION;
END
请记住使用sys.columns作为列循环(我假设您使用SQL 2005/2008)。
SET @col = 0;
WHILE EXISTS (SELECT TOP 1 * FROM sys.columns WHERE object_id = OBJECT_ID('MyTable') AND column_id > @col)
BEGIN
SELECT TOP 1 @col = column_id FROM sys.columns
WHERE object_id = OBJECT_ID('MyTable') AND column_id > @col ORDER BY column_id ASC;
SET @sql ....
INSERT INTO #stmt ....
END
删除第4行@colcount int
和正在进行的逗号。删除信息架构选择。
答案 2 :(得分:1)
不要使用任何类型的循环触发器。不要使用动态SQl或调用存储过程或发送电子邮件。所有这些事情在触发器中都是不恰当的。
如果tyou想要使用动态sql,则使用它创建脚本来创建触发器。并为您想要审计的每个表创建一个审计表(我们实际上每个表都有两个),否则由于锁定“一个表来统治所有表”而导致性能问题。