Я использую специальный запрос, который добавляет все эти общие столбцы (я называю их столбцами аудита) ко всем таблицам (используя курсор, перемещающийся по информационной схеме), что позволяет легко применять их к новым базам данных.
Мои столбцы (специфичные для SQL Server):
RowId UNIQUEIDENTIFIER NOT NULL DEFAULT (NEWID()),
Created DATETIME NOT NULL DEFAULT (GETDATE()),
Creator NVARCHAR(256) NOT NULL DEFAULT(SUSER_SNAME())
RowStamp TIMESTAMP NOT NULL
Теперь в полностью нормализованной схеме мне понадобится только RowId
, которая будет ссылаться на таблицу аудита, содержащую другие строки. На самом деле, если подумать, мне бы хотелось, чтобы я пошел по этому пути - главным образом потому, что он делает таблицы некрасивыми (фактически я оставляю эти столбцы вне диаграмм схемы базы данных).
Однако при работе с очень большими наборами данных вы получаете повышение производительности, если эти данные находятся в таблице, и у меня до сих пор не возникало проблем с этой системой.
Редактировать: Можно также опубликовать код для добавления столбцов аудита:
DECLARE AuditCursor CURSOR FOR
SELECT TABLE_SCHEMA, TABLE_NAME from INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND OBJECTPROPERTY(OBJECT_ID(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)), 'IsMSShipped') = 0
AND TABLE_NAME NOT IN ('sysdiagrams')
AND TABLE_NAME NOT LIKE 'dt_%'
-- NB: you could change the above to only do it for certain tables
OPEN AuditCursor
DECLARE @schema varchar(128), @table varchar(128)
FETCH NEXT FROM AuditCursor INTO @schema, @table
WHILE @@FETCH_STATUS -1
BEGIN
PRINT '* Adding audit columns to [' + @schema + '].[' + @table + ']...'
IF NOT EXISTS (SELECT NULL
FROM information_schema.columns
WHERE table_schema = @schema
AND table_name = @table
AND column_name = 'Created')
BEGIN
DECLARE @sql_created varchar(max)
SELECT @sql_created = 'ALTER TABLE [' + @schema + '].[' + @table + '] ADD [Created] DATETIME NOT NULL CONSTRAINT [DF_' + @table + '_Created] DEFAULT (GETDATE())'
EXEC ( @sql_created )
PRINT ' - Added Created'
END
ELSE
PRINT ' - Created already exists, skipping'
IF NOT EXISTS (SELECT NULL
FROM information_schema.columns
WHERE table_schema = @schema
AND table_name = @table
AND column_name = 'Creator')
BEGIN
DECLARE @sql_creator varchar(max)
SELECT @sql_creator = 'ALTER TABLE [' + @schema + '].[' + @table + '] ADD [Creator] VARCHAR(256) NOT NULL CONSTRAINT [DF_' + @table + '_Creator] DEFAULT (SUSER_SNAME())'
EXEC ( @sql_creator )
PRINT ' - Added Creator'
END
ELSE
PRINT ' - Creator already exists, skipping'
IF NOT EXISTS (SELECT NULL
FROM information_schema.columns
WHERE table_schema = @schema
AND table_name = @table
AND column_name = 'RowId')
BEGIN
DECLARE @sql_rowid varchar(max)
SELECT @sql_rowid = 'ALTER TABLE [' + @schema + '].[' + @table + '] ADD [RowId] UNIQUEIDENTIFIER NOT NULL CONSTRAINT [DF_' + @table + '_RowId] DEFAULT (NEWID())'
EXEC ( @sql_rowid )
PRINT ' - Added RowId'
END
ELSE
PRINT ' - RowId already exists, skipping'
IF NOT EXISTS (SELECT NULL
FROM information_schema.columns
WHERE table_schema = @schema
AND table_name = @table
AND (column_name = 'RowStamp' OR data_type = 'timestamp'))
BEGIN
DECLARE @sql_rowstamp varchar(max)
SELECT @sql_rowstamp = 'ALTER TABLE [' + @schema + '].[' + @table + '] ADD [RowStamp] ROWVERSION NOT NULL'
EXEC ( @sql_rowstamp )
PRINT ' - Added RowStamp'
END
ELSE
PRINT ' - RowStamp or another timestamp already exists, skipping'
-- basic tamper protection against non-SA users
PRINT ' - setting DENY permission on audit columns'
DECLARE @sql_deny VARCHAR(1000)
SELECT @sql_deny = 'DENY UPDATE ON [' + @schema + '].[' + @table + '] ([Created]) TO [public]'
+ 'DENY UPDATE ON [' + @schema + '].[' + @table + '] ([RowId]) TO [public]'
+ 'DENY UPDATE ON [' + @schema + '].[' + @table + '] ([Creator]) TO [public]'
EXEC (@sql_deny)
PRINT '* Completed processing [' + @schema + '].[' + @table + ']'
FETCH NEXT FROM AuditCursor INTO @schema, @table
END
CLOSE AuditCursor
DEALLOCATE AuditCursor
GO