Estou tentando gerar gatilhos em várias tabelas para forçar os dados a maiúsculas e aparar espaços à esquerda e à direita quando os dados são inseridos ou atualizados. O problema que estou tendo é determinar na trigger uma forma geral de vincular a pseudotabela INSERTED à tabela base. Nem todas as tabelas têm o mesmo nome de PK, embora muitas tenham uma coluna exclusiva chamada _DataChanges_RowID em cada tabela que pode ser usada. Eu sei que posso inspecionar o PK e gerar os gatilhos usando essas colunas, mas antes de ver isso, queria saber se existe uma maneira genérica de unir a pseudotabela INSERTED à tabela base que é mais simples e independente de coluna.
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
;
Não, não há uma maneira genérica e independente de coluna para unir a
INSERTED
pseudotabela à tabela base. Você precisará usar uma junção interna convencional e fazer referência à coluna PK (ou colunas, se a chave for composta) explicitamente no predicado da junção.Portanto, se a coluna PK não for a mesma em cada uma das tabelas para as quais você está gerando os acionadores, não há como consultar metadados para descobrir o nome da coluna a ser usada. Você pode fazer isso usando as exibições compatíveis com o padrão SQL (bem, mais ou menos)
INFORMATION_SCHEMA
( exemplo ) ou usando os catálogos do sistema SQL Server nativo ( exemplo ).