3

我想在 SQL Server 2008 中的特定表上应用所有事务。

我发现上次使用此脚本更新表的时间:

SELECT OBJECT_NAME(OBJECT_ID) AS DatabaseName, last_user_update,*
FROM sys.dm_db_index_usage_stats
WHERE database_id = DB_ID( 'DBName')
AND OBJECT_ID=OBJECT_ID('tableName')

我想知道该表的所有事务(插入、更新、删除)、它们的日期时间以及应用的查询。

做这个的最好方式是什么?

4

4 回答 4

2

在合理的时间内做到这一点的唯一方法是使用第三方工具(正如 Martin 在第一条评论中所说),例如ApexSQL Log,它可以读取事务日志并获取您需要的信息。

请注意,为了使其工作,您的数据库必须处于完全恢复模式,因为那是 SQL Server 记录可以稍后重建的完整事务详细信息的时间。

另一种选择是研究如何使用未记录的 fn_dblog 函数,但这会花费您更多时间,并且您将无法读取分离的日志或事务日志备份。

于 2013-09-17T13:05:09.743 回答
2

创建一个触发器,该触发器将创建一个新表 Emp_audit 并在对表employee 进行任何更改时向其添加新元组

create trigger my_trigger on Employees

AFTER INSERT, UPDATE, DELETE
AS
DECLARE @What varchar(30);
DECLARE @Who varchar(30);
DECLARE @for int;
DECLARE @At time;
DECLARE @COUNTI int;
DECLARE @COUNTD int;
select @COUNTI = COUNT(*) from inserted;
select @COUNTD = COUNT(*) from deleted;
set @Who = SYSTEM_USER;
set @At = CURRENT_TIMESTAMP;

if( @COUNTD = 0 and @COUNTI = 1)
    begin
    set @What = 'insert';
    select @for = EmployeeID from inserted i;
    end
else 
    begin
    if( @COUNTD = 1 and @COUNTI = 0)
        begin 
        set @What = 'delete';
        select @for = EmployeeID from deleted i;
        end
    else  
        begin
        set @What = 'update';
        select @for = EmployeeID from inserted i;
        end
    end

     INSERT INTO EMP_Audit Values (@What, @Who, @for, @At);
于 2014-01-29T05:15:36.860 回答
0

您最好针对此需求设置审计,而不是尝试从事务日志中追溯提取此信息。

如果您使用的是企业版,则可以使用内置的SQL Server 审计功能,否则通过触发器记录所需信息应该相对简单。

于 2011-10-16T13:59:49.710 回答
0

您可以创建自己的事务日志

第 1 步:为事务日志创建自己的表

CREATE TABLE [dbo].[TransactionLogs](
 [TransactionLogID] [bigint] IDENTITY(1,1) NOT NULL,
 [Query] [nvarchar](max) NOT NULL,
 [DateCreated] [datetime] NOT NULL,
CONSTRAINT [PK_TransactionLogs] PRIMARY KEY CLUSTERED 
(
 [TransactionLogID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, 
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

第 2 步:创建创建日志的存储过程。(注意:将 YourTablePKColumn 替换为您的表主键列。)

create procedure  [dbo].[sp_CreateQueryLogs]
(
    @Query nvarchar(max) = null output,
    @TableName nvarchar(100),
    @YourTablePKColumn nvarchar(30),
    @QueryTypeID tinyint --0 insert, 1 update, 2 delete
) 
as
begin
    declare @object_id bigint, @column_name nvarchar(100), @collation_name nvarchar(50), @column_name_id nvarchar(100) = null, @column_names nvarchar(max) = '', @column_values nvarchar(max) = '', @column_names_create nvarchar(max) = '', @values nvarchar(max) = '', @user_type_id int, @max_length nvarchar(10), @type_name nvarchar(50), @CreateTempTable nvarchar(max) = '', @is_nullable bit, @value nvarchar(max) = ''

    
    create table #tmpValues(ColumnValues nvarchar(max))

    insert into #tmpValues(ColumnValues)
    exec('select CAST ( ( select * from ' + @TableName + ' where YourTablePKColumn = ' + @YourTablePKColumn + '
                    FOR XML PATH(''tr''), TYPE 
        ) AS NVARCHAR(MAX) )')

    select @values = ColumnValues from #tmpValues

    if @QueryTypeID = 0 --insert
        set @Query = 'insert into ' + @TableName + '('
    else if @QueryTypeID = 1 --update
        set @Query = 'update ' + @TableName + ' set '
    else if @QueryTypeID = 2 --dalete
        set @Query = 'delete ' + @TableName + ' '

    select @object_id = object_id from sys.tables where name = @TableName

    if not cursor_status('local','columnCursor') <= -1
    begin
        close columnCursor;
        deallocate columnCursor;
    end
    declare columnCursor cursor local for
    select name, user_type_id, convert(nvarchar(10), max_length), is_nullable from sys.columns where object_id = @object_id order by column_id ;
    open columnCursor;
    fetch next from columnCursor 
    into @column_name, @user_type_id, @max_length, @is_nullable;
    while @@FETCH_STATUS = 0
    begin
        select @type_name = name, @collation_name = collation_name from sys.types where user_type_id = @user_type_id
        if @column_name_id is null
            set @column_name_id = @column_name
        else
        begin
            set @column_names += @column_name + ', '
            declare @value_keys_start nvarchar(max) = '<' + @column_name + '>', @value_keys_end nvarchar(max) = '</' + @column_name + '>'

            if charindex(@value_keys_start,@values,1) = 0
            begin
                if @QueryTypeID = 0 --insert
                    set @column_values += 'null,'
                else if @QueryTypeID = 1 --update
                    set @column_values += @column_name + ' = null,'
            end
            else
            begin
                if @QueryTypeID = 0 --insert
                    if @collation_name is null and not (@type_name like '%date%' or @type_name like '%time%')
                        set @column_values += substring(@values, charindex(@value_keys_start,@values,1) + len(@value_keys_start), charindex(@value_keys_end,@values,1) - (charindex(@value_keys_start,@values,1) + len(@value_keys_start))) + ','
                    else if @type_name like '%date%' or @type_name like '%time%'
                        set @column_values += '''' + replace(substring(@values, charindex(@value_keys_start,@values,1) + len(@value_keys_start), charindex(@value_keys_end,@values,1) - (charindex(@value_keys_start,@values,1) + len(@value_keys_start))),'T',' ') + ''','
                    else 
                        set @column_values += '''' + replace(substring(@values, charindex(@value_keys_start,@values,1) + len(@value_keys_start), charindex(@value_keys_end,@values,1) - (charindex(@value_keys_start,@values,1) + len(@value_keys_start))),'''','''''') + ''','
                else if @QueryTypeID = 1 --update
                    if @collation_name is null and not (@type_name like '%date%' or @type_name like '%time%')
                        set @column_values += @column_name + '=' + substring(@values, charindex(@value_keys_start,@values,1) + len(@value_keys_start), charindex(@value_keys_end,@values,1) - (charindex(@value_keys_start,@values,1) + len(@value_keys_start))) + ','
                    else if @type_name like '%date%' or @type_name like '%time%'
                        set @column_values += @column_name + '=' + '''' + replace(substring(@values, charindex(@value_keys_start,@values,1) + len(@value_keys_start), charindex(@value_keys_end,@values,1) - (charindex(@value_keys_start,@values,1) + len(@value_keys_start))),'T',' ') + ''','
                    else 
                        set @column_values +=  @column_name + '=' + '''' + replace(substring(@values, charindex(@value_keys_start,@values,1) + len(@value_keys_start), charindex(@value_keys_end,@values,1) - (charindex(@value_keys_start,@values,1) + len(@value_keys_start))),'''','''''') + ''','
            end
        end
        fetch next from columnCursor 
        into @column_name, @user_type_id, @max_length, @is_nullable;
    end
    if not cursor_status('local','columnCursor') <= -1
    begin
        close columnCursor;
        deallocate columnCursor;
    end

    if @QueryTypeID = 0 --insert
        set @Query += substring(@column_names,1,len(@column_names) - 1) + ')
        values (' + substring(@column_values,1,len(@column_values) - 1) + ')'
    else if @QueryTypeID = 1 --update or delete
        set @Query += substring(@column_values,1,len(@column_values) - 1) + ' where YourTablePKColumn = ' + @YourTablePKColumn
    else
        set @Query += ' where YourTablePKColumn = ' + @YourTablePKColumn

end

第 3 步:为您想要拥有事务日志的表创建触发器

    CREATE TRIGGER trg_MyTrigger ON YouTableName 
AFTER INSERT, DELETE, UPDATE
AS 
BEGIN
    SET NOCOUNT ON;

    declare @TableName nvarchar(100) = 'YouTableName', @Query nvarchar(max), @QueryTypeID tinyint, @YourTablePKColumn nvarchar(30)

    if exists(select * from deleted) and exists(select * from inserted) 
    begin
        set @QueryTypeID = 1
        if not cursor_status('local','updatedCursor') <= -1
        begin
            close updatedCursor;
            deallocate updatedCursor;
        end
        declare updatedCursor cursor local for
        select cast(YourTablePKColumn as nvarchar(30)) from inserted;
        open updatedCursor;
        fetch next from updatedCursor 
        into @YourTablePKColumn;
        while @@FETCH_STATUS = 0
        begin
            exec dbo.sp_CreateQueryLogs @Query = @Query output, @TableName = @TableName, @YourTablePKColumn = @YourTablePKColumn, @QueryTypeID = @QueryTypeID
            insert into TransactionLogs
                     (Query, DateCreated)
            values (@Query,getdate())
            fetch next from updatedCursor 
            into @YourTablePKColumn;
        end
        if not cursor_status('local','updatedCursor') <= -1
        begin
            close updatedCursor;
            deallocate updatedCursor;
        end
    end
    else if exists(select * from deleted) and not exists(select * from inserted)
    begin
        set @QueryTypeID = 2
        if not cursor_status('local','deletedCursor') <= -1
        begin
            close deletedCursor;
            deallocate deletedCursor;
        end
        declare deletedCursor cursor local for
        select cast(YourTablePKColumn as nvarchar(30)) from deleted;
        open deletedCursor;
        fetch next from deletedCursor 
        into @YourTablePKColumn;
        while @@FETCH_STATUS = 0
        begin
            exec dbo.sp_CreateQueryLogs @Query = @Query output, @TableName = @TableName, @YourTablePKColumn = @YourTablePKColumn, @QueryTypeID = @QueryTypeID
            insert into TransactionLogs
                     (Query, DateCreated)
            values (@Query,getdate())
            fetch next from deletedCursor 
            into @YourTablePKColumn;
        end
        if not cursor_status('local','deletedCursor') <= -1
        begin
            close deletedCursor;
            deallocate deletedCursor;
        end
    end
    else
    begin
        set @QueryTypeID = 0
        if not cursor_status('local','insertedCursor') <= -1
        begin
            close insertedCursor;
            deallocate insertedCursor;
        end
        declare insertedCursor cursor local for
        select cast(YourTablePKColumn as nvarchar(30)) from inserted;
        open insertedCursor;
        fetch next from insertedCursor 
        into @YourTablePKColumn;
        while @@FETCH_STATUS = 0
        begin
            exec dbo.sp_CreateQueryLogs @Query = @Query output, @TableName = @TableName, @YourTablePKColumn = @YourTablePKColumn, @QueryTypeID = @QueryTypeID
            insert into TransactionLogs
                     (Query, DateCreated)
            values (@Query,getdate())
            fetch next from insertedCursor 
            into @YourTablePKColumn;
        end
        if not cursor_status('local','insertedCursor') <= -1
        begin
            close insertedCursor;
            deallocate insertedCursor;
        end
    end

END
GO
于 2021-08-10T13:35:00.377 回答