Skip to content

Commit 6ebc284

Browse files
committed
Adding sql script in repo
1 parent fb0488f commit 6ebc284

File tree

1 file changed

+263
-0
lines changed

1 file changed

+263
-0
lines changed
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
-- The MIT License (MIT)
2+
--
3+
-- Copyright (c) 2015 Philip Doxakis
4+
--
5+
-- Permission is hereby granted, free of charge, to any person obtaining a copy
6+
-- of this software and associated documentation files (the "Software"), to deal
7+
-- in the Software without restriction, including without limitation the rights
8+
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
-- copies of the Software, and to permit persons to whom the Software is
10+
-- furnished to do so, subject to the following conditions:
11+
--
12+
-- The above copyright notice and this permission notice shall be included in all
13+
-- copies or substantial portions of the Software.
14+
--
15+
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
-- SOFTWARE.
22+
23+
/*
24+
Script Name:
25+
Audit trail script for SQL Server Database
26+
Author:
27+
Philip Doxakis
28+
Customize:
29+
You can exclude table in the script.
30+
Follow comments in the script: "Specify table to exclude here:"
31+
Description:
32+
Install a complete audit trail on selected database.
33+
Optional: Add "USE [DatabaseName];" at the top of the script.
34+
Step:
35+
- Remove all triggers starting with "tr_audit_"
36+
- Add "Audit" table if not found on the database
37+
- Add triggers for almost all tables (this can be customized).
38+
Limitations:
39+
- Audit table is "Audit"
40+
- Audit trigger start with "tr_audit_"
41+
- Do not support datatype: image
42+
(Based on https://msdn.microsoft.com/en-us/library/ms187928.aspx)
43+
*/
44+
45+
DECLARE @DatabaseName VARCHAR(255);
46+
SELECT @DatabaseName = TABLE_CATALOG FROM information_schema.columns
47+
48+
PRINT 'Starting script...'
49+
PRINT ''
50+
PRINT 'Environnement:'
51+
PRINT ' Server:'
52+
PRINT ' ' + CAST(SERVERPROPERTY('ServerName') AS VARCHAR(255))
53+
PRINT ' Edition:'
54+
PRINT ' ' + CAST(SERVERPROPERTY('Edition') AS VARCHAR(255))
55+
PRINT ' Database name:'
56+
PRINT ' ' + @DatabaseName
57+
PRINT ''
58+
59+
PRINT 'Starting: Removing all triggers starting with tr_audit_'
60+
DECLARE @TriggerName VARCHAR(255);
61+
DECLARE MY_CURSOR_FOR_TRIGGER CURSOR
62+
LOCAL STATIC READ_ONLY FORWARD_ONLY
63+
FOR
64+
-- Get list of trigger in current database
65+
SELECT
66+
sysobjects.name AS trigger_name
67+
FROM sysobjects
68+
WHERE
69+
sysobjects.type = 'TR' AND
70+
sysobjects.name LIKE 'tr_audit_%'
71+
OPEN MY_CURSOR_FOR_TRIGGER
72+
FETCH NEXT FROM MY_CURSOR_FOR_TRIGGER INTO @TriggerName
73+
WHILE @@FETCH_STATUS = 0
74+
BEGIN
75+
DECLARE @sql VARCHAR(250)
76+
77+
-- Remove current trigger
78+
SET @sql = 'DROP TRIGGER ' + @TriggerName
79+
PRINT 'Removing trigger: ' + @TriggerName
80+
EXEC (@sql)
81+
82+
FETCH NEXT FROM MY_CURSOR_FOR_TRIGGER INTO @TriggerName
83+
END
84+
CLOSE MY_CURSOR_FOR_TRIGGER
85+
DEALLOCATE MY_CURSOR_FOR_TRIGGER
86+
PRINT 'Finished: Removing all triggers starting with tr_audit_'
87+
PRINT ''
88+
89+
PRINT 'Starting: Make sure Audit table exists'
90+
IF NOT EXISTS (SELECT * FROM sysobjects WHERE id = OBJECT_ID(N'[dbo].[Audit]'))
91+
BEGIN
92+
PRINT 'Adding Audit table in the database'
93+
CREATE TABLE Audit
94+
(Type CHAR(1),
95+
TableName VARCHAR(128),
96+
PK VARCHAR(1000),
97+
FieldName VARCHAR(128),
98+
OldValue VARCHAR(MAX),
99+
NewValue VARCHAR(MAX),
100+
UpdateDate datetime)
101+
END
102+
GO
103+
PRINT 'Finished: Make sure Audit table exists'
104+
PRINT ''
105+
106+
PRINT 'Starting: Create audit trigger for all tables'
107+
DECLARE @TableName VARCHAR(255);
108+
DECLARE MY_CURSOR_FOR_TABLE CURSOR
109+
LOCAL STATIC READ_ONLY FORWARD_ONLY
110+
FOR
111+
SELECT DISTINCT TABLE_NAME
112+
FROM information_schema.columns
113+
WHERE OBJECTPROPERTY(OBJECT_ID(TABLE_CATALOG + '.' + TABLE_SCHEMA + '.' + TABLE_NAME), 'IsView') = 0
114+
OPEN MY_CURSOR_FOR_TABLE
115+
FETCH NEXT FROM MY_CURSOR_FOR_TABLE INTO @TableName
116+
WHILE @@FETCH_STATUS = 0
117+
BEGIN
118+
If @TableName != 'Audit' -- Table used by audit trigger
119+
AND LEFT(@TableName, 7) <> 'aspnet_'
120+
AND LEFT(@TableName, 9) <> 'webpages_'
121+
-- Specify table to exclude here:
122+
-- Copy paste line bellow to specify table to exclude more table:
123+
--AND @TableName != 'VersionInfo' -- Table used by FluentMigrator
124+
BEGIN
125+
PRINT 'Adding trigger for table: ' + @TableName
126+
DECLARE @sql VARCHAR(8000)
127+
SET @sql = 'CREATE TRIGGER tr_audit_' + @TableName + '
128+
ON [' + @TableName + '] FOR INSERT, UPDATE, DELETE
129+
AS
130+
DECLARE @field INT,
131+
@maxfield INT,
132+
@char INT,
133+
@mask INT,
134+
@fieldname VARCHAR(128),
135+
@TableName VARCHAR(128),
136+
@PKCols VARCHAR(1000),
137+
@sql VARCHAR(8000),
138+
@UpdateDate VARCHAR(21),
139+
@UserName VARCHAR(128),
140+
@Type CHAR(1),
141+
@PKSelect VARCHAR(1000)
142+
143+
SET NOCOUNT ON
144+
145+
--You will need to change @TableName to match the table to be audited
146+
SELECT @TableName = ''' + @TableName + '''
147+
148+
-- date and user
149+
SELECT @UserName = SYSTEM_USER,
150+
@UpdateDate = CONVERT(VARCHAR(8), GETDATE(), 112)
151+
+ '' '' + CONVERT(VARCHAR(12), GETDATE(), 114)
152+
153+
-- Action
154+
IF EXISTS (SELECT * FROM inserted)
155+
IF EXISTS (SELECT * FROM deleted)
156+
SELECT @Type = ''U''
157+
ELSE
158+
SELECT @Type = ''I''
159+
ELSE
160+
SELECT @Type = ''D''
161+
162+
-- get list of columns
163+
SELECT * INTO #ins FROM inserted
164+
SELECT * INTO #del FROM deleted
165+
166+
-- Get primary key columns for full outer join
167+
SELECT @PKCols = COALESCE(@PKCols + '' and'', '' on'')
168+
+ '' i.'' + c.COLUMN_NAME + '' = d.'' + c.COLUMN_NAME
169+
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
170+
171+
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
172+
WHERE pk.TABLE_NAME = @TableName
173+
AND CONSTRAINT_TYPE = ''PRIMARY KEY''
174+
AND c.TABLE_NAME = pk.TABLE_NAME
175+
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
176+
177+
-- Get primary key select for insert
178+
SELECT @PKSelect = COALESCE(@PKSelect+''+'','''')
179+
+ ''''''<'' + COLUMN_NAME
180+
+ ''=''''+convert(varchar(100),
181+
coalesce(i.'' + COLUMN_NAME +'',d.'' + COLUMN_NAME + ''))+''''>''''''
182+
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
183+
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
184+
WHERE pk.TABLE_NAME = @TableName
185+
AND CONSTRAINT_TYPE = ''PRIMARY KEY''
186+
AND c.TABLE_NAME = pk.TABLE_NAME
187+
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
188+
189+
IF @PKCols IS NULL
190+
BEGIN
191+
RAISERROR(''no PK on table %s'', 16, -1, @TableName)
192+
RETURN
193+
END
194+
195+
SELECT @field = 0,
196+
@maxfield = MAX(ORDINAL_POSITION)
197+
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @TableName
198+
WHILE @field < @maxfield
199+
BEGIN
200+
SELECT @field = MIN(ORDINAL_POSITION)
201+
FROM INFORMATION_SCHEMA.COLUMNS
202+
WHERE TABLE_NAME = @TableName
203+
AND ORDINAL_POSITION > @field
204+
IF @field IS NOT NULL
205+
BEGIN
206+
SELECT
207+
@field = MIN(ORDINAL_POSITION),
208+
@char = (column_id - 1) / 8 + 1,
209+
@mask = POWER(2, (column_id - 1) % 8),
210+
@fieldname = name
211+
FROM SYS.COLUMNS SC
212+
INNER JOIN INFORMATION_SCHEMA.COLUMNS ISC
213+
ON SC.name = ISC.COLUMN_NAME
214+
WHERE object_id = OBJECT_ID(@TableName)
215+
AND TABLE_NAME = @TableName
216+
AND ORDINAL_POSITION = @field
217+
GROUP BY column_id, name
218+
219+
IF (SUBSTRING(COLUMNS_UPDATED(), @char, 1) & @mask) > 0
220+
OR @Type IN (''I'',''D'')
221+
BEGIN
222+
SELECT @sql = ''
223+
INSERT Audit ( Type,
224+
TableName,
225+
PK,
226+
FieldName,
227+
OldValue,
228+
NewValue,
229+
UpdateDate)
230+
SELECT '''''' + @Type + '''''',''''''
231+
+ @TableName + '''''','' + @PKSelect
232+
+ '','''''' + @fieldname + ''''''''
233+
+ '',convert(varchar(MAX),d.'' + @fieldname + '')''
234+
+ '',convert(varchar(MAX),i.'' + @fieldname + '')''
235+
+ '','''''' + @UpdateDate + ''''''''
236+
+ '' from #ins i full outer join #del d''
237+
+ @PKCols
238+
+ '' where i.'' + @fieldname + '' <> d.'' + @fieldname
239+
+ '' or (i.'' + @fieldname + '' is null and d.''
240+
+ @fieldname
241+
+ '' is not null)''
242+
+ '' or (i.'' + @fieldname + '' is not null and d.''
243+
+ @fieldname
244+
+ '' is null)''
245+
EXEC (@sql)
246+
END
247+
END
248+
END'
249+
250+
EXEC(@sql)
251+
END
252+
ELSE
253+
BEGIN
254+
PRINT 'Trigger not added for table: ' + @TableName
255+
END
256+
FETCH NEXT FROM MY_CURSOR_FOR_TABLE INTO @TableName
257+
END
258+
CLOSE MY_CURSOR_FOR_TABLE
259+
DEALLOCATE MY_CURSOR_FOR_TABLE
260+
PRINT 'Finished: Create audit trigger for all tables'
261+
262+
PRINT ''
263+
PRINT 'Finished!'

0 commit comments

Comments
 (0)