我正在尝试在多个表上生成触发器以强制数据为大写并在插入或更新数据时修剪前导和尾随空格。我遇到的问题是在触发器中确定一种将 INSERTED 伪表绑定到基表的通用方法。并非所有表都具有相同的 PK 名称,尽管许多表在每个表中都有一个可以使用的名为 _DataChanges_RowID 的唯一列。我知道我可以检查 PK 并使用这些列生成触发器,但在查看之前,我想知道是否有一种通用方法可以将 INSERTED 伪表连接到基表,这种方法更简单且与列无关。
DECLARE @TriggerTemplate AS VARCHAR(MAX) =
'CREATE TRIGGER <<SchemaName>>.<<TriggerName>> ON <<FullTableName>>
AFTER INSERT, UPDATE
AS BEGIN
IF (ROWCOUNT_BIG() = 0)
RETURN;
IF TRIGGER_NESTLEVEL(( SELECT object_id FROM sys.triggers WHERE QUOTENAME(name) = ''<<TriggerName>>'' ), ''AFTER'', ''DML'') < 1
UPDATE <<FullTableName>>
SET <<SQLColumnUpdate>>
WHERE <<FullTableName>>._DataChanges_RowID IN (SELECT _DataChanges_RowID FROM INSERTED);
END;
GO
sp_settriggerorder <<SchemaName>>.<<TriggerName>>, ''FIRST'', ''INSERT'';
sp_settriggerorder <<SchemaName>>.<<TriggerName>>, ''FIRST'', ''UPDATE'';
GO
';
WITH cols AS
(
SELECT
FullTableName = QUOTENAME(S.name) + '.' + QUOTENAME(T.name),
SchemaName = QUOTENAME(S.name),
TableName = QUOTENAME(T.name),
ColumnName = QUOTENAME(C.name)
FROM
sys.columns C
INNER JOIN sys.tables T
ON C.object_id = T.object_id
INNER JOIN sys.schemas S
ON T.schema_id = S.schema_id
WHERE
C.is_computed = 0
AND C.system_type_id IN (
167, -- varchar
175, -- char
231, -- nvarchar
239 -- nchar
)
)
, TablesAndColumns AS (
SELECT
cols.FullTableName
, cols.TableName
, cols.SchemaName
, TriggerName = QUOTENAME('TRG_DATA_CONFORM_' + cols.FullTableName)
, SQLColumnUpdate = STUFF((SELECT ', ' + c2.ColumnName + ' = UPPER(LTRIM(RTRIM(' + c2.ColumnName + ')))'
FROM cols c2
WHERE c2.FullTableName = cols.FullTableName
ORDER BY c2.ColumnName
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 2, '')
FROM cols
GROUP BY cols.FullTableName, cols.SchemaName, cols.TableName
)
SELECT FullTableName
, SQLTrigger = REPLACE(REPLACE(REPLACE(REPLACE(@TriggerTemplate, '<<SQLColumnUpdate>>', SQLColumnUpdate), '<<TriggerName>>', TriggerName), '<<FullTableName>>', FullTableName), '<<SchemaName>>', SchemaName)
, KeyOK = CASE WHEN EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE QUOTENAME(TABLE_SCHEMA) = SchemaName AND QUOTENAME(TABLE_NAME) = TableName AND COLUMN_NAME = '_DataChanges_RowID') THEN 1 ELSE 0 END
FROM TablesAndColumns
;
不,没有通用的、与列无关的方法将
INSERTED
伪表连接到基表。您将需要使用传统的内部联接并在联接谓词中显式引用 PK 列(或列,如果键是复合的)。因此,如果 PK 列在您为其生成触发器的每个表中都不相同,则无法通过查询元数据来找出要使用的列名。您可以使用符合 SQL 标准(或多或少)的
INFORMATION_SCHEMA
视图(example)或使用本机 SQL Server 系统目录(example)来做到这一点。