We have a SQL Server 2008 Enterprise database with two different schemas, a locked one that we maintain and an open one that we allow outside development teams to add to and
The Redgate options are as follows.
1) The easiest way you can start auditing schema changes is by installing DLM Dashboard. This is a free tool that alerts and logs all changes using DDL triggers, and will include the information you ask for.
2) As is already mentioned by Andy Davies, the right way to do this is to start source controlling your schema in the same way as you do for application code. Once you've done this, you can increase your database lifecycle management maturity by including your database in continuous integration and release management practices.
You could look at putting your database under source control. Perhaps making each outside team take a branch or fork of your database. This gives you auditting of changes via commits and the ability to choose which changes to merge in and/or review/edit those changes before merging in.
Look at http://www.red-gate.com/products/sql-development/sql-source-control/ for one product that is available.
Combined with a solution like Github or Bitbucket that open up your source control repositories more directly to external contributors via internet.
For the second question you can consider triggers as an option. In the following example, information about the event that fired the trigger is captured using the SQL Server’s EVENTDATA() function. The SQL script creates DDL trigger that captures CREATE, ALTER, and DROP events on a database level (although, triggers can be created on the server level to capture events for all databases on the server; ON ALL SERVER option should be used, instead of ON DATABASE)
CREATE TRIGGER Audit_DDL ON DATABASE
FOR CREATE_TABLE , ALTER_TABLE , DROP_TABLE
AS
DECLARE
@event xml;
SET @event = EVENTDATA(
);
INSERT INTO Audit_DDL_Events
VALUES( REPLACE( CONVERT( varchar( 50
) , @event.query( 'data(/EVENT_INSTANCE/PostTime)'
)
) , 'T' , ' '
) ,
CONVERT( varchar( 150
) , @event.query( 'data(/EVENT_INSTANCE/LoginName)'
)
) ,
CONVERT( varchar( 150
) , @event.query( 'data(/EVENT_INSTANCE/UserName)'
)
) ,
CONVERT( varchar( 150
) , @event.query( 'data(/EVENT_INSTANCE/DatabaseName)'
)
) ,
CONVERT( varchar( 150
) , @event.query( 'data(/EVENT_INSTANCE/SchemaName)'
)
) ,
CONVERT( varchar( 150
) , @event.query( 'data(/EVENT_INSTANCE/ObjectName)'
)
) ,
CONVERT( varchar( 150
) , @event.query( 'data(/EVENT_INSTANCE/ObjectType)'
)
) ,
CONVERT( varchar( max
) , @event.query( 'data(/EVENT_INSTANCE/TSQLCommand/CommandText)'
)
)
);
An appropriate storage table for the auditing data from EVENTDATA XML must be created also:
CREATE TABLE Audit_DDL_Events( DDL_Event_Time datetime ,
DDL_Login_Name varchar( 150
) ,
DDL_User_Name varchar( 150
) ,
DDL_Database_Name varchar( 150
) ,
DDL_Schema_Name varchar( 150
) ,
DDL_Object_Name varchar( 150
) ,
DDL_Object_Type varchar( 150
) ,
DDL_Command varchar( max
)
);
I've got a system that uses a DDL trigger for exactly this type of thing. It works well enough for my needs. It was originally developed on Sql Server 2005, and now lives on a Sql Server 2008R2 system. It's similar to the one described by the link in Aaron Bertrand's comment.
Create a table similar to this one.
CREATE TABLE [dbo].[SchemaLog](
[SchemaLogID] [int] IDENTITY(1,1) NOT NULL,
[PostTimeUtc] [datetime] NOT NULL,
[DatabaseUser] [nvarchar](128) NOT NULL,
[Event] [nvarchar](128) NOT NULL,
[Schema] [nvarchar](128) NULL,
[Object] [nvarchar](128) NULL,
[TSQL] [nvarchar](max) NOT NULL,
[XmlEvent] [xml] NOT NULL,
CONSTRAINT [PK_SchemaLog_1] PRIMARY KEY CLUSTERED
(
[SchemaLogID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Make sure everyone has insert permissions on the table then create a ddl trigger similar to this.
CREATE TRIGGER [ddlDatabaseTriggerLog] ON DATABASE FOR DDL_DATABASE_LEVEL_EVENTS AS
BEGIN
SET NOCOUNT ON;
DECLARE @data XML;
DECLARE @schema sysname;
DECLARE @object sysname;
DECLARE @eventType sysname;
SET @data = EVENTDATA();
SET @eventType = @data.value('(/EVENT_INSTANCE/EventType)[1]', 'sysname');
SET @schema = @data.value('(/EVENT_INSTANCE/SchemaName)[1]', 'sysname');
SET @object = @data.value('(/EVENT_INSTANCE/ObjectName)[1]', 'sysname')
IF @object IS NOT NULL
PRINT ' ' + @eventType + ' - ' + @schema + '.' + @object;
ELSE
PRINT ' ' + @eventType + ' - ' + @schema;
IF @eventType IS NULL
PRINT CONVERT(nvarchar(max), @data);
INSERT [dbo].[SchemaLog] (
[PostTimeUtc]
, [DatabaseUser]
, [Event]
, [Schema]
, [Object]
, [TSQL]
, [XmlEvent] )
VALUES (
GETUTCDATE()
, CONVERT(sysname, CURRENT_USER)
, @eventType
, CONVERT(sysname, @schema)
, CONVERT(sysname, @object)
, @data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'nvarchar(max)')
, @data );
END;
View to select changes in order
create view SchemaLogOrdered
as
SELECT top 10000 *
FROM dbo.SchemaLog
ORDER BY SchemaLogID DESC