在mssql上创建表之后的数据库触发器

时间:2017-01-19 12:04:50

标签: sql sql-server stored-procedures triggers

我在表创建后获得了一个数据库触发器。

CREATE TRIGGER  tr_Timestamps_TableTriggersCreation
ON DATABASE
AFTER CREATE_TABLE
AS
BEGIN 
SET NOCOUNT ON
DECLARE @tableName SYSNAME
    DECLARE @schemaName SYSNAME = NULL
    DECLARE @totalRows INT = 0;

    SELECT @tableName = EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]','SYSNAME') 

    SELECT TOP 1 @schemaName = s.name
    FROM sys.tables t
    JOIN sys.columns c ON c.object_id = t.object_id
    JOIN sys.schemas s ON s.schema_id = t.schema_id
    WHERE t.name = @tableName
    AND c.name = 'ID'

    IF (@schemaName != '')
    BEGIN
        EXEC u_general.sp_Timestamps_TriggerForTableCreation @tableName, @schemaName, 'I'
        EXEC u_general.sp_Timestamps_TriggerForTableCreation @tableName, @schemaName, 'U'
    END

它背后的想法是为在该数据库上创建的每个表创建2个触发器。

我的问题如下,

当有人使用MSSQL'编辑器'并使用' Design'选项而不是编写脚本来进行更改,例如标记列以及“否则为空”,更改数据类型等... 我的数据库触发器将其计为新表创建,并启动为该表创建触发器的过程。 最终结果是它尝试再次创建这些触发器,并且我收到一条错误消息,表明这些触发器已经存在。

ALTER PROCEDURE [u_general].[sp_Timestamps_TriggerForTableCreation] ( @tableName sysname, @schemaName sysname, @actionType char(1))
AS


   DECLARE @TrigerName NVARCHAR(50)
   DECLARE @AfterActionName NVARCHAR(50)

   IF @actionType = 'I'
   BEGIN
        SET @TrigerName = 'tr_Timestamps_CaptureAfterInsert_' + @tableName
        SET @AfterActionName = 'INSERT'
   END
   ELSE -- 'U'
   BEGIN
        SET @TrigerName = 'tr_Timestamps_CaptureAfterUpdate_' + @tableName
        SET @AfterActionName = 'UPDATE'
   END

 DECLARE @SQLCommand nvarchar(max)= 
'CREATE TRIGGER ' + @TrigerName +'
ON ' + @schemaName + '.' + @tableName  +
' AFTER '+ @AfterActionName +'
AS
    DECLARE @auditBody XML
    DECLARE @RowID int

    SELECT @RowID = INSERTED.ID FROM INSERTED
    SELECT @auditBody = 
        ''<Timestamps_Request>
            <DataBaseName>'' + DB_NAME() + ''</DataBaseName>
            <SchemaName>'' + ''' + @schemaName + ''' + ''</SchemaName>
            <TableName>'' + ''' + @tableName + '''+ ''</TableName>
            <RowID>'' + CAST(@RowID AS NVARCHAR(30)) + ''</RowID>
            <Action>'' + '''+@actionType+''' + ''</Action>
        </Timestamps_Request>''

    EXEC u_general.sp_Timestamps_SendBrokerMessage @FromService = ''Timestamps_RequestService'',
    @ToService   = ''Timestamps_ProcessingService'',
    @Contract    = ''Timestamps_Contract'',
    @MessageType = ''Timestamps_Request'',
    @MessageBody = @auditBody  ';

    EXEC sp_executeSQL @SQLCommand

我的问题是,

我可以做些什么来确保每次有人决定使用设计师来改变这种情况时都不会发生这种情况。一张桌子?

P.S。根据我的理解,它与SSMS(导致drop和create?)及其工作方式有关,这就是为什么我在使用脚本修改表而不是MSSQL设计器时没有这个问题。

1 个答案:

答案 0 :(得分:1)

在直接回答之前

快速注释。

DDL EventsCREATE_TABLE一起使用并确认您未在触发器定义中使用Alter_TABLE,因为CREATE_TABLEAlter_TABLE是完全分开的事件。< / p>

按照下一个演示了解更多详情。

<强>演示: -

Create table table1 (col1 int, col2 nvarchar(10) not null )
go

Create TRIGGER NoCreateNewTables ON DATABASE 
    FOR  CREATE_TABLE
AS 

Print 'Prevent Table Creation'
BEGIN
    ROLLBACK;
END    

GO

Alter Table1通过下一个:

ALTER TABLE table1 ALTER COLUMN col2 nvarchar(10) NULL

<强>结果: -

enter image description here

Create新表Table2通过下一个:

Create table table2 (col1 int, col2 nvarchar(10) not null )

<强>结果: -

enter image description here

SSMS怎么样

直接答案从这里开始

在某些情况下,SQL Server在使用SSMS设计器时删除并重新创建表:

常见情况: -

  • 添加新列。
  • 更改列的“允许空值”设置。
  • 更改表格中的列顺序。
  • 更改列数据类型。

经过一些调查,我注意到Object_Name通过SSMS设计师改编的Tmp_SSMS开头。

所以根据这个信息,我们可以通过创建触发器来阻止通过/* Create Trigger for Preventing altering table Via SSMS while table recreated */ Create TRIGGER TrgPreventAlterTableIfTableRecreatedViaSSMSDesign ON DATABASE FOR CREATE_TABLE AS BEGIN DECLARE @eventInfo XML, @ObjectName varchar(100) SET @eventInfo = EVENTDATA() select @ObjectName = CONVERT(SYSNAME, @eventInfo.query('data(/EVENT_INSTANCE/ObjectName)')) if (Left(@ObjectName,3) = 'Tmp') begin exec sp_addmessage 50001, 16, N'Cannot modify Table Via SSMS, use [Alter Table] Code instead'; RAISERROR(50001,16,1) exec sp_dropmessage 50001 rollback; end END 设计器改变表,以防止在重新创建表时从SSMS中更改表。

<强>演示: -

Table1

现在尝试改变SSMS通过NULL设计师从NOT NULL到{{1}}

将提出下一个流行消息: -

enter image description here

enter image description here