|
|
|
SSC-Addicted
      
Group: General Forum Members
Last Login: Yesterday @ 10:34 AM
Points: 494,
Visits: 2,158
|
|
According to BOL, DDL trigger respond to CREATE, ALTER, DROP + other T-SQL commands.
I'm currently using two triggers for when a DB is created/dropped but I want to deal with databases that get renamed.
I have a backup schedule table. When a database is created, a trigger fires which creates 2 years’ worth of entries for this new database in the backupschedule table.
If a database is deleted, another trigger removes the entries from the backupschedule table.
However, I had a problem with one database over the weekend because it got renamed and my backupschedule table didn't get updated.
The trigger that generates the backupschedule looks like this:
CREATE TRIGGER [DDLTriggerCreateDatabaseBackupSchedule] ON ALL SERVER FOR CREATE_DATABASE AS declare @data xml declare @DBName varchar(256) set @data = eventdata() set @DBName = @data.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'varchar(256)')
INSERT INTO QbaseDBAUtility.dbo.backupschedule(backupdate, Backupweekday, databasename, BackupType)
SELECT DATEADD(DD,N,dateadd(dd, 0, DATEDIFF(dd, 0, getdate()))) AS backupdate, DATENAME(DW,DATEADD(DD,N,dateadd(dd, 0, DATEDIFF(dd, 0, getdate())))) AS Backupweekday ,b.name ,CASE WHEN N % 14 = 0 THEN 'F' ELSE 'D' END AS backuptype FROM QbaseDBAUtility.dbo.Tally AS a CROSS JOIN sys.databases as b WHERE N < 780 and name = @DBName Is it possible to make one if the database is renamed?
----------------------------------- http://www.SQL4n00bs.com
|
|
|
|
|
SSC Rookie
      
Group: General Forum Members
Last Login: Friday, May 03, 2013 3:06 AM
Points: 42,
Visits: 285
|
|
Hello,
Renaming a database will include the keyword 'ALTER'.The backup schedule was unaffected by renaming of the database because the triggers you have acts on events of 'CREATE' and 'DROP' and not for 'ALTER' statement. You need to create another DDL trigger which tracks the 'ALTER DATABASE' conditions and performs the desired actions (Updating the backup schedule in this case).
Let me know if this solves your query.
Regards..
|
|
|
|
|
SSC-Addicted
      
Group: General Forum Members
Last Login: Yesterday @ 10:34 AM
Points: 494,
Visits: 2,158
|
|
Thanks arunyadav007, I understand this part but I'm not really sure how to actually implement the ALTER_DATABASE trigger.
When the new trigger fires, how do I access the old database name and the new one? This is the bit that I'm not sure about.
Once I have this info, it's easy enough to update the backupschedule table.
----------------------------------- http://www.SQL4n00bs.com
|
|
|
|
|
SSC-Addicted
      
Group: General Forum Members
Last Login: Yesterday @ 10:34 AM
Points: 494,
Visits: 2,158
|
|
This is my new ALTER_DATABASE trigger:
CREATE TRIGGER [DDLTriggerRenameDatabaseBackupSchedule] ON ALL SERVER FOR ALTER_DATABASE AS DECLARE @data XML DECLARE @NewDBName VARCHAR(256) DECLARE @PreviousDBName VARCHAR(256) SET @data = eventdata() SET @PreviousDBName = @data.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'varchar(256)') SET @NewDBName = @data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'varchar(256)') SET @NewDBName = REVERSE(SUBSTRING(REVERSE(@NewDBName), 1, CHARINDEX('=', REVERSE(@NewDBName))-1)) UPDATE QbaseDBAUtility.dbo.BackupSchedule SET DatabaseName = @NewDBName WHERE DatabaseName = @PreviousDBName
GO .......but this seems to fire even when I create a database. I have a feeling when I create a database using SSMS, SQL Server is executing a series of T-SQL statements which also includes an ALTER statement.
----------------------------------- http://www.SQL4n00bs.com
|
|
|
|
|
SSChampion
        
Group: General Forum Members
Last Login: Yesterday @ 6:41 PM
Points: 11,648,
Visits: 27,760
|
|
arunyadav007 pointed you in the right direction, here's a code model for your trigger.
I',m not sure if you are just inserting the changes, updating existing, or what; i'd think there needs to be a trigger to delete rows from your main history table for when something gets dropped.
--see http://schemas.microsoft.com/sqlserver/2006/11/eventdata/events.xsd --for the values available for various events CREATE TRIGGER [DDLTriggerCreateDatabaseBackupSchedule] ON ALL Server --I need the sa context in case i need to access a table that the user, who cna create/alter database, but does not have access to dbMail or objects used for logging --i.e. db_owner rights in a given database lets a user alter their own database, but they certainly might not have access to objects used below. WITH EXECUTE AS 'sa' FOR Create_Database,Alter_Database -- Captures a Create/Alter Database Event AS BEGIN --SERVER TRIGGER DECLARE @EventType varchar(128), @PostTime datetime, @SPID int, @ServerName varchar(128), @LoginName varchar(128), @DatabaseName varchar(128), @TSQLCommand varchar(128), @mySubject varchar(300), @data XML SET @data = EVENTDATA() --load our values to variables in case we need them SELECT @EventType = @data.value('(/EVENT_INSTANCE/EventType)[1]' ,'varchar(128)' ), @PostTime = @data.value('(/EVENT_INSTANCE/PostTime)[1]' ,'datetime' ), @SPID = @data.value('(/EVENT_INSTANCE/SPID)[1]' ,'int' ), @ServerName = @data.value('(/EVENT_INSTANCE/ServerName)[1]' ,'varchar(128)' ), @LoginName = @data.value('(/EVENT_INSTANCE/LoginName)[1]' ,'varchar(128)' ), @DatabaseName = @data.value('(/EVENT_INSTANCE/DatabaseName)[1]' ,'varchar(128)' ), @TSQLCommand = @data.value('(/EVENT_INSTANCE/TSQLCommand)[1]' ,'varchar(128)' )
IF @EventType = 'CREATE_DATABASE' BEGIN INSERT INTO QbaseDBAUtility.dbo.backupschedule(backupdate, Backupweekday, databasename, BackupType) SELECT DATEADD(DD,N,dateadd(dd, 0, DATEDIFF(dd, 0, getdate()))) AS backupdate, DATENAME(DW,DATEADD(DD,N,dateadd(dd, 0, DATEDIFF(dd, 0, getdate())))) AS Backupweekday ,b.name ,CASE WHEN N % 14 = 0 THEN 'F' ELSE 'D' END AS backuptype FROM QbaseDBAUtility.dbo.Tally AS a CROSS JOIN sys.databases as b WHERE N < 780 and name = @DatabaseName END IF @EventType = 'ALTER_DATABASE' BEGIN PRINT 'This is Where we isnert or update to teh special table' END END --SERVER TRIGGER
Lowell
--There is no spoon, and there's no default ORDER BY in sql server either. Actually, Common Sense is so rare, it should be considered a Superpower. --my son
|
|
|
|
|
SSChampion
        
Group: General Forum Members
Last Login: Yesterday @ 6:41 PM
Points: 11,648,
Visits: 27,760
|
|
the event data is going to have the new database name...it's already been changed by thetime you get to the ddl trigger, unless you force a rollback.
you could rollback , get the name, and then re-execute the query i guess, but that's a lot of effort for somethign simple. otherwise you'll have to parse the sql statement to get the previous database name...that's going to be a little harder.
i think you might want to consider saving the db_id() of the database...then it doesn't matter the whether the name changes or not.
select db_id('Sandbox') select database_name(7)
Lowell
--There is no spoon, and there's no default ORDER BY in sql server either. Actually, Common Sense is so rare, it should be considered a Superpower. --my son
|
|
|
|
|
SSC-Addicted
      
Group: General Forum Members
Last Login: Yesterday @ 10:34 AM
Points: 494,
Visits: 2,158
|
|
Lowell (12/3/2012)
the event data is going to have the new database name...it's already been changed by thetime you get to the ddl trigger, unless you force a rollback. you could rollback , get the name, and then re-execute the query i guess, but that's a lot of effort for somethign simple. otherwise you'll have to parse the sql statement to get the previous database name...that's going to be a little harder. i think you might want to consider saving the db_id() of the database...then it doesn't matter the whether the name changes or not. select db_id('Sandbox') select database_name(7)
I like the idea of using the database ID however, from the above, I already have the code that works it out:
SET @data = eventdata() SET @PreviousDBName = @data.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'varchar(256)') SET @NewDBName = @data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'varchar(256)') SET @NewDBName = REVERSE(SUBSTRING(REVERSE(@NewDBName), 1, CHARINDEX('=', REVERSE(@NewDBName))-1)) UPDATE QbaseDBAUtility.dbo.BackupSchedule SET DatabaseName = @NewDBName WHERE DatabaseName = @PreviousDBName Although I'm not sure how the above would work if the database was renamed via the GUI.
I also like your idea of using just one trigger to handle the three event types but the problem is, when I create a database, SQL Server is also firing the ALTER_DATABASE event type. Very strange....
This is how the new trigger looks like:
CREATE TRIGGER [DDLTriggerCreateAlterOrDropDatabaseBackupSchedule] ON ALL SERVER FOR CREATE_DATABASE, ALTER_DATABASE, DROP_DATABASE AS DECLARE @data xml DECLARE @DBName varchar(256) DECLARE @EventType varchar(128) DECLARE @NewDBName varchar(256) SET @data = eventdata() SET @DBName = @data.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'varchar(256)') SET @EventType = @data.value('(/EVENT_INSTANCE/EventType)[1]', 'varchar(128)')
IF @EventType = 'CREATE_DATABASE' BEGIN INSERT INTO QbaseDBAUtility.dbo.backupschedule(backupdate, Backupweekday, databasename, BackupType) SELECT DATEADD(DD,N,dateadd(dd, 0, DATEDIFF(dd, 0, getdate()))) AS backupdate, DATENAME(DW,DATEADD(DD,N,dateadd(dd, 0, DATEDIFF(dd, 0, getdate())))) AS Backupweekday ,b.name, CASE WHEN N % 14 = 0 THEN 'F' ELSE 'D' END AS backuptype FROM QbaseDBAUtility.dbo.Tally AS a CROSS JOIN sys.databases as b WHERE N < 780 and name = @DBName END ELSE IF @EventType = 'ALTER_DATABASE' BEGIN SET @NewDBName = @data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'varchar(256)') SET @NewDBName = reverse(substring(reverse(@NewDBName), 1, charindex('=', reverse(@NewDBName))-1)) UPDATE QbaseDBAUtility.dbo.BackupSchedule SET DatabaseName = @NewDBName WHERE DatabaseName = @DBName -- original DB name END ELSE BEGIN DELETE QbaseDBAUtility.dbo.backupschedule WHERE databaseName = @DBName END
GO As I said, this isn't working properly because when I create a new database, it fires both the CREATE_DATABASE and ALTER_DATABASE parts of the trigger. This is why I wodnered if in the background SQL Server is running an ALTER DATABASE command after the CREATE DATABASE when one creates it via the SSMS GUI.
----------------------------------- http://www.SQL4n00bs.com
|
|
|
|
|
SSChampion
        
Group: General Forum Members
Last Login: Yesterday @ 6:41 PM
Points: 11,648,
Visits: 27,760
|
|
yeah, i just scripted a CREATE DATABASE from the GUI; you can see it does a bunch of alters for the properties after it does the create:
CREATE DATABASE [Example] ON PRIMARY ( NAME = N'Example', FILENAME = N'F:\SQLData\DEV223\Example.mdf' , SIZE = 3072KB , FILEGROWTH = 1024KB ) LOG ON ( NAME = N'Example_log', FILENAME = N'F:\SQLData\DEV223\Example_log.ldf' , SIZE = 1024KB , FILEGROWTH = 10%) GO ALTER DATABASE [Example] SET COMPATIBILITY_LEVEL = 100 GO ALTER DATABASE [Example] SET ANSI_NULL_DEFAULT OFF GO ALTER DATABASE [Example] SET ANSI_NULLS OFF GO ALTER DATABASE [Example] SET ANSI_PADDING OFF GO ALTER DATABASE [Example] SET ANSI_WARNINGS OFF GO ALTER DATABASE [Example] SET ARITHABORT OFF GO ALTER DATABASE [Example] SET AUTO_CLOSE OFF GO ALTER DATABASE [Example] SET AUTO_CREATE_STATISTICS ON GO ALTER DATABASE [Example] SET AUTO_SHRINK OFF GO ALTER DATABASE [Example] SET AUTO_UPDATE_STATISTICS ON GO ALTER DATABASE [Example] SET CURSOR_CLOSE_ON_COMMIT OFF GO ALTER DATABASE [Example] SET CURSOR_DEFAULT GLOBAL GO ALTER DATABASE [Example] SET CONCAT_NULL_YIELDS_NULL OFF GO ALTER DATABASE [Example] SET NUMERIC_ROUNDABORT OFF GO ALTER DATABASE [Example] SET QUOTED_IDENTIFIER OFF GO ALTER DATABASE [Example] SET RECURSIVE_TRIGGERS OFF GO ALTER DATABASE [Example] SET DISABLE_BROKER GO ALTER DATABASE [Example] SET AUTO_UPDATE_STATISTICS_ASYNC OFF GO ALTER DATABASE [Example] SET DATE_CORRELATION_OPTIMIZATION OFF GO ALTER DATABASE [Example] SET PARAMETERIZATION SIMPLE GO ALTER DATABASE [Example] SET READ_WRITE GO ALTER DATABASE [Example] SET RECOVERY FULL GO ALTER DATABASE [Example] SET MULTI_USER GO ALTER DATABASE [Example] SET PAGE_VERIFY CHECKSUM GO USE [Example] GO IF NOT EXISTS (SELECT name FROM sys.filegroups WHERE is_default=1 AND name = N'PRIMARY') ALTER DATABASE [Example] MODIFY FILEGROUP [PRIMARY] DEFAULT GO
Lowell
--There is no spoon, and there's no default ORDER BY in sql server either. Actually, Common Sense is so rare, it should be considered a Superpower. --my son
|
|
|
|
|
SSC-Addicted
      
Group: General Forum Members
Last Login: Yesterday @ 10:34 AM
Points: 494,
Visits: 2,158
|
|
Thanks for the confirmation.
I have managed to resolve the problem with the following trigger which I have tested and seems to work like a charm!
CREATE TRIGGER [DDLTriggerCreateAlterOrDropDatabaseBackupSchedule] ON ALL SERVER FOR CREATE_DATABASE, ALTER_DATABASE, DROP_DATABASE AS SET NOCOUNT ON DECLARE @data xml DECLARE @DBName varchar(256) DECLARE @EventType varchar(128) DECLARE @NewDBName varchar(256) SET @data = eventdata() SET @DBName = @data.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'varchar(256)') SET @EventType = @data.value('(/EVENT_INSTANCE/EventType)[1]', 'varchar(128)') IF @EventType = 'CREATE_DATABASE' BEGIN INSERT INTO QbaseDBAUtility.dbo.backupschedule(backupdate, Backupweekday, databasename, BackupType) SELECT DATEADD(DD,N,dateadd(dd, 0, DATEDIFF(dd, 0, getdate()))) AS backupdate, DATENAME(DW,DATEADD(DD,N,dateadd(dd, 0, DATEDIFF(dd, 0, getdate())))) AS Backupweekday ,ltrim(rtrim(b.name)), CASE WHEN N % 14 = 0 THEN 'F' ELSE 'D' END AS backuptype FROM QbaseDBAUtility.dbo.Tally AS a CROSS JOIN sys.databases as b WHERE N < 780 and name = @DBName END ELSE IF @EventType = 'ALTER_DATABASE' BEGIN SET @NewDBName = @data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'varchar(256)') IF @NewDBName like '%MODIFY NAME%' BEGIN SET @NewDBName = replace(replace(ltrim(rtrim(reverse(substring(reverse(@NewDBName), 1, charindex('=', reverse(@NewDBName))-1)))), '[', ''), ']', '') UPDATE QbaseDBAUtility.dbo.BackupSchedule SET DatabaseName = @NewDBName WHERE DatabaseName = ltrim(rtrim(@DBName)) -- original DB name END END ELSE IF @EventType = 'DROP_DATABASE' BEGIN DELETE QbaseDBAUtility.dbo.backupschedule WHERE databaseName = @DBName END ELSE BEGIN SELECT 0 END
SET NOCOUNT OFF
----------------------------------- http://www.SQL4n00bs.com
|
|
|
|
|
SSChampion
        
Group: General Forum Members
Last Login: Yesterday @ 6:41 PM
Points: 11,648,
Visits: 27,760
|
|
glad it's working for you!
one more thing to consider: if you create a new database via a RESTORE, that does not trigger the CREATE_DATABASE event. that triggers the event AUDIT_BACKUP_RESTORE_EVENT, which is not a DDL event (so you cannot modify your trigger to capture that too),
you have to add an extended event AUDIT_BACKUP_RESTORE_EVENT to the server to capture and do the equivalent of what you are doing now under CREATE_DATABASE.
just one more thing to consider.
Lowell
--There is no spoon, and there's no default ORDER BY in sql server either. Actually, Common Sense is so rare, it should be considered a Superpower. --my son
|
|
|
|