当前触发如下:
CREATE TRIGGER TestTrigger
ON DATABASE
FOR ALTER_TABLE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @FULL_STATEMENT SYSNAME
SELECT @FULL_STATEMENT = EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')
print('The following SQL statement was executed:')
print('')
print (@FULL_STATEMENT)
print('')
print('Next step is to work out how to single out the added column name')
ROLLBACK
END
然后我运行以下SQL语句:
USE [a_Database]
ALTER TABLE dbo.TABLE
ADD TestColumn varchar(50)
它输出以下内容:
执行了以下SQL语句:
ALTER TABLE dbo.TABLE
ADD TestColumn varchar(50)
下一步是弄清楚如何挑出添加的列名
Msg 3609,Level 16,State 2,Line 2
交易在触发器中结束。批次已中止。
最终目标是挑出“TestColumn”以确保它不包含可能破坏内部程序的特定字符。 “TestColumn”将是一个有效的名称,但“Test.Column”不会,例如。
将单个输出并将其传递给新变量(“@ColumnName”?)以检查不需要的字符的最佳方法是什么?
答案 0 :(得分:1)
You need to bear in mind that an alter statement can add more than one column. If you look at the XML generated for an alter column statement you will get a better idea:
ALTER TABLE dbo.EventTest ADD NewColumn1 INT, NewColumn2 INT;
----------------------------
<EVENT_INSTANCE>
<EventType>ALTER_TABLE</EventType>
<PostTime>2015-06-30T14:28:30.790</PostTime>
<SPID>67</SPID>
<ServerName>XXXXXX</ServerName>
<LoginName>XXXXXX</LoginName>
<UserName>dbo</UserName>
<DatabaseName>XXXXXX</DatabaseName>
<SchemaName>dbo</SchemaName>
<ObjectName>EventTest</ObjectName>
<ObjectType>TABLE</ObjectType>
<AlterTableActionList>
<Create>
<Columns>
<Name>NewColumn1</Name>
<Name>NewColumn2</Name>
</Columns>
</Create>
</AlterTableActionList>
<TSQLCommand>
<SetOptions ANSI_NULLS="ON" ANSI_NULL_DEFAULT="ON" ANSI_PADDING="ON" QUOTED_IDENTIFIER="ON" ENCRYPTED="FALSE" />
<CommandText>ALTER TABLE dbo.EventTest ADD NewColumn1 INT, NewColumn1 INT;</CommandText>
</TSQLCommand>
</EVENT_INSTANCE>
So since you can add multiple columns, you need to check multiple columns, to get your columns lists you can use:
SELECT ColumnName = Cols.value('.', 'SYSNAME')
FROM EVENTDATA().nodes('EVENT_INSTANCE/AlterTableActionList/Create/Columns') x (Cols);
Then you could simply use EXISTS
to check against a list of reserved names etc, and check for unwanted characters:
IF EXISTS
( SELECT 1
FROM ( SELECT ColumnName = Cols.value('.', 'SYSNAME')
FROM EVENTDATA().nodes('EVENT_INSTANCE/AlterTableActionList/Create/Columns') x (Cols)
) AS t
WHERE PATINDEX('%[.@!-]%', t.ColumnName) > 0 -- USE PATTERN MATCH TO CHECK FOR UNWANTED CHARACTERS
OR EXISTS
( SELECT 1
FROM dbo.ReservedColumnNames AS rc
WHERE rc.Name = t.ColumnName
)
)
BEGIN
RAISERROR(...)
ROLLBACK;
END
Another thing to consider is that sp_rename
will fire a different event, and you probably want to track this too. The XML here looks like:
<EVENT_INSTANCE>
<EventType>RENAME</EventType>
....
<SchemaName>dbo</SchemaName>
<ObjectName>NewColumn</ObjectName>
<ObjectType>COLUMN</ObjectType>
<TargetObjectName>EventTest</TargetObjectName>
<TargetObjectType>TABLE</TargetObjectType>
<NewObjectName>NewColumn2</NewObjectName>
<Parameters>
<Param>dbo.EventTest.NewColumn</Param>
<Param>NewColumn2</Param>
<Param>COLUMN</Param>
</Parameters>
<TSQLCommand>
<SetOptions ANSI_NULLS="ON" ANSI_NULL_DEFAULT="ON" ANSI_PADDING="ON" QUOTED_IDENTIFIER="ON" ENCRYPTED="FALSE" />
<CommandText>EXECUTE SP_RENAME 'dbo.EventTest.NewColumn', 'NewColumn2', 'COLUMN';</CommandText>
</TSQLCommand>
</EVENT_INSTANCE>
So here you would need to track it slightly differently, since it can only be one column at a time, you don't need to worry about nodes:
SELECT EVENTDATA().value('EVENT_INSTANCE[1]/NewObjectName[1]', 'SYSNAME')
WHERE EVENTDATA().value('EVENT_INSTANCE[1]/EventType[1]', 'VARCHAR(13)') = 'RENAME'
AND EVENTDATA().value('EVENT_INSTANCE[1]/ObjectType[1]', 'VARCHAR(13)') = 'COLUMN';