Jaster, 마지막으로 귀하의 검색어에 대한 해결책이 있습니다.
동적 스크립트로 필요한 테이블의 이름을 말할 수 있습니다. 스크립트는이 테이블에서 INSERT/UPDATE/DELETE
작업에 발생하는 동적 트리거를 만들어 모든 열 (데이터 유형이 text, ntext 및 image 인 열 제외)에 걸쳐 언급 된 테이블 테이블의 데이터 변경을 관리합니다. 요구 사항에 따라 작업을 변경할 수 있습니다. TableName
및 ModifiedDate
도 HISTORY 표에 포함되어있어 쉽게 찾을 수 있습니다.
다음은 솔루션 단계입니다. 아래 임시 테이블에서 제공하는 정보
IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME= 'History')
CREATE TABLE [dbo].[History](
[Id] [uniqueidentifier] NOT NULL CONSTRAINT [DF_History_Id] DEFAULT (newsequentialid()),
[Tablename] VARCHAR(150),
[ObjectId] VARCHAR(1500) NOT NULL,
[Timestamp] [datetime] NOT NULL CONSTRAINT [DF_History_Timestamp] DEFAULT (getdate()),
[ChangingUser] [varchar](max) NOT NULL CONSTRAINT [DF_History_ChangingUser] DEFAULT (suser_sname()),
[Column] [varchar](max) NOT NULL,
[OldValue] [nvarchar](max) NULL,
[NewValue] [nvarchar](max) NULL,
[ModifiedDate] Datetime NULL
CONSTRAINT [PK_History] PRIMARY KEY CLUSTERED
(
[Id] 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]
IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME= 'T1')
BEGIN
CREATE TABLE [dbo].[T1](
[Id] [uniqueidentifier] NOT NULL CONSTRAINT [DF_T1_Id] DEFAULT (newsequentialid()),
[Title] text NULL,
[Amount] [int] NULL,
[Price] [decimal](18, 7) NULL,
[Version] [datetime] NOT NULL,
CONSTRAINT [PK_T1] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
INSERT INTO [T1] ([Title],[Amount],[Price],[Version]) VALUES ('Abc',3,372500000 ,'2016-09-01 11:49:33.473'),
(NULL,1,273000000 ,'2016-09-02 11:49:33.473'),
('Storm Catcher',10,NULL,'2016-09-01 11:49:33.473')
END
를 사용하여 샘플 테스트 환경을 만들기
, 당신은 데이터 변경 사항을 추적하고 싶어하는 테이블 이름을 삽입해야합니다.
IF OBJECT_ID('tempdb..#FiltedTableList') IS NOT NULL
DROP TABLE #FiltedTableList
GO
CREATE TABLE #FiltedTableList
(ID INT IDENTITY(1,1),
TableName VARCHAR(150))
INSERT INTO #FiltedTableList (TableName)
SELECT 'T1' --here we have only one table to track the changes
여기 마지막 단계가됩니다. 아래 동적 쿼리를 실행하십시오. 그래서 여기
DECLARE @TableName sysname,@Counter INT,@Dynamsql varchar(MAX)
SELECT @Counter=MAX(ID) FROM #FiltedTableList
SET NOCOUNT ON
WHILE (@Counter !=0)
BEGIN
SELECT @TableName= TableName
FROM #FiltedTableList
WHERE [email protected]
DECLARE @ColumnFilter VARCHAR (MAX)
SELECT @ColumnFilter=Stuff(( Select ', ' + C.COLUMN_NAME
From INFORMATION_SCHEMA.COLUMNS As C Where C.TABLE_NAME = @TableName
AND c.DATA_TYPE NOT IN ('text','ntext','image')
Order By C.ORDINAL_POSITION For Xml Path('') ), 1, 2, '')
IF OBJECT_ID('tempdb..##MagInserted') IS NOT NULL
DROP TABLE ##MagInserted
IF OBJECT_ID('tempdb..##MagDeleted') IS NOT NULL
DROP TABLE ##MagDeleted
EXEC('IF OBJECT_ID (''' + @TableName+ '_LogTracker'', ''TR'') IS NOT NULL DROP TRIGGER ' + @TableName+ '_LogTracker')
SELECT @Dynamsql =
'CREATE TRIGGER ' + @TableName+ '_LogTracker ON ' + @TableName+ ' FOR INSERT, UPDATE, DELETE
AS
DECLARE @column int , @maxColumn int , @char int,@columnname varchar(128) , @TableName varchar(128) , @KeyColumn varchar(1000) , @Dynamsql varchar(2000) ,@dataquery VARCHAR(MAX),
@ModifiedDate varchar(21), @UserName varchar(128) , @key int , @Type char(1) , @PKFieldSelect varchar(1000),@PKValueSelect varchar(1000)
SELECT @TableName = ''' + @TableName+ ''';
SELECT @UserName = system_user , @ModifiedDate = convert(varchar(8), getdate(), 112) + '' '' + convert(varchar(12), getdate(), 114);
SELECT '+ @ColumnFilter+' INTO ##MagInserted FROM inserted;SELECT '+ @ColumnFilter+' INTO ##MagDeleted FROM deleted;
SELECT @KeyColumn = COALESCE(@KeyColumn + '' and'', '' on'') + '' i.'' + c.COLUMN_NAME + '' = d.'' + c.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS kc JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE c ON c.TABLE_NAME = kc.TABLE_NAME and c.CONSTRAINT_NAME = kc.CONSTRAINT_NAME
WHERE kc.TABLE_NAME = @TableName AND CONSTRAINT_TYPE = ''PRIMARY KEY''
SELECT @PKFieldSelect = COALESCE(@PKFieldSelect+''+'','''') + '''''''' + COLUMN_NAME + ''''''''
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS kc JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE c ON c.TABLE_NAME = kc.TABLE_NAME and c.CONSTRAINT_NAME = kc.CONSTRAINT_NAME
WHERE kc.TABLE_NAME = @TableName AND CONSTRAINT_TYPE = ''PRIMARY KEY''
SELECT @PKValueSelect = coalesce(@PKValueSelect+''+'','''') + ''convert(varchar(100), coalesce(i.'' + COLUMN_NAME + '',d.'' + COLUMN_NAME + ''))''
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS kc JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE c ON c.TABLE_NAME = kc.TABLE_NAME and c.CONSTRAINT_NAME = kc.CONSTRAINT_NAME
WHERE kc.TABLE_NAME = @TableName AND CONSTRAINT_TYPE = ''PRIMARY KEY''
SELECT @column = 0 , @maxColumn = max(ORDINAL_POSITION) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @TableName
WHILE @column < @maxColumn
BEGIN
SELECT @column = min(ORDINAL_POSITION) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @TableName AND ORDINAL_POSITION > @column
SELECT @key = (@column - 1)% 8 + 1; SELECT @key = power(2,@key - 1);SELECT @char = ((@column - 1)/8) + 1
IF SUBSTRING(COLUMNS_UPDATED(),@char, 1) & @key > 0 OR @Type IN (''I'',''D'')
BEGIN
SELECT @columnname = COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @TableName and ORDINAL_POSITION = @column
SELECT @Dynamsql = ''insert History (TableName,[ObjectId], [Column], OldValue, NewValue, ModifiedDate, ChangingUser)''
SELECT @Dynamsql = @Dynamsql + '' select '''''' + @TableName + ''''''''
SELECT @Dynamsql = @Dynamsql + '','' + @PKValueSelect
SELECT @Dynamsql = @Dynamsql + '','''''' + @columnname + ''''''''
SELECT @Dynamsql = @Dynamsql + '',convert(varchar(1000),d.'' + @columnname + '')''
SELECT @Dynamsql = @Dynamsql + '',convert(varchar(1000),i.'' + @columnname + '')''
SELECT @Dynamsql = @Dynamsql + '','''''' + @ModifiedDate + ''''''''
SELECT @Dynamsql = @Dynamsql + '','''''' + @UserName + ''''''''
SELECT @Dynamsql = @Dynamsql + '' from ##MagInserted i full outer join ##MagDeleted d''
SELECT @Dynamsql = @Dynamsql + @KeyColumn
SELECT @Dynamsql = @Dynamsql + '' where i.'' + @columnname + '' <> d.'' + @columnname
SELECT @Dynamsql = @Dynamsql + '' or (i.'' + @columnname + '' is null and d.'' + @columnname + '' is not null)''
SELECT @Dynamsql = @Dynamsql + '' or (i.'' + @columnname + '' is not null and d.'' + @columnname + '' is null)''
EXEC (@Dynamsql)
END END '
SELECT @Dynamsql
EXEC(@Dynamsql)
SET @[email protected]
END
테스트 케이스 및 출력 :
먼저, 열을 지정하지 않고 콤보를 쓰거나 삽입하거나 선택하지 마십시오. 둘째,'COLUMNS_UPDATED()'를 사용하지 않는 것이 좋습니다. https://msdn.microsoft.com/en-au/library/ms186329.aspx. 이 정보를 저장하는 방법을 언급하지 않았습니다 –
ofc 그 예입니다. 내 기록 테이블의 레이아웃이 내가 어떻게 그것을 저장하고 싶은지 보여줍니다. 사용자와 시간을 줄이는 것이 명백합니다. columns_updated()에서 볼 수 있듯이 동적 쿼리를 만들고 실행해야합니다. – Jaster
사과 귀하의 게시물을 제대로 읽지 못하고 테이블을 놓쳤습니다. 어쨌든 열을 식별하고로드해야하기 때문에이 테이블에로드하려면 동적 SQL이 필요할 것입니다. 따라서 동적 SQL, 하드 코딩 된 SQL 또는 데이터베이스 미러링과 같은 하위 수준 복제 시스템을 원하는지 결정하십시오. 하드 코딩 된 SQL을 사용하면 실제로 자동 생성 할 수 있습니다. 테이블을 검사하고 올바른 생성 트리거 문 ... 코드 자동 생성과 같은 문자열을 내보내는 proc을 작성하십시오. –