SQL Server - Analisando qual campo foi alterado via trigger

|


Muitas vezes precisamos validar se uma "coluna x" foi alterado dentro de uma trigger.
No SQL Server, temos duas maneiras de fazer tal validação.

1) A função Update(nome_coluna) retorna um valor boolean se tal coluna for alterada;
2) E a função Columns_Updated() que retorna um varbinary;

1) Para comparar duas colunas de uma tabela sem se independente das outras, o Update resolve bem o problema.

If (Update(col1) And Update(col2))
   Print 'Coluna 1 e Coluna 2 foram alteradas.'


2) Agora, se você quiser comparar uma coluna que depende de outras, aí você terá que utilizar o Columns_Updated(). Essa função retorna uma variável onde cada byte representa 8 colunas da sua tabela. Começando da esquerda para a direita, o primeiro byte referencia da 1ª a 8ª coluna. O segundo byte referencia da 9ª a 16ª coluna e assim por diante.

Falando em linguagem binária, temos 8 bits em que cada posição desse bit referencia a 8 colunas da sua tabela.
Exemplo 1: 00000000 (Nenhuma alteração nas colunas)
Exemplo 2: 00000100 (A 3ª coluna foi alterada)
Exemplo 3: 10100000 (A 6ª e 8ª colunas foram alteradas)

Em decimal, temos:

Exemplo 1: 0 (Nenhuma alteração nas colunas)
Exemplo 2: 4 (A 3ª coluna foi alterada)
Exemplo 3: 160 (A 6ª e 8ª colunas foram alteradas)

Bom, chega de falar de teoria e vamos ao código que tudo vai ficar mais simples.
-- Exemplo 1:
-- O valor da comparação é feito em decimal e é utilizado uma comparação binária "&" para retonar o valor inteiro da função Columns_Updated()

If (Columns_Updated() & 4) = 4
   Print 'Somente a terceira coluna foi alterada'
   
-- Exemplo 2:

If (Columns_Updated() & 0) = 0
   Print 'Não houve alteração na tabela'
   
-- Exemplo 3:

If (Columns_Updated() & 160) = 160
   Print 'Colunas 6 e 8 foram alteradas'


2a) Mas e se a minha tabela tiver mais de 8 colunas? Bom, aí teremos que ler cada byte separadamente, pois cada byte corresponde somente a 8 colunas como já foi dito anteriormente. Os exemplos abaixo são somente para uma tabela de até 16 colunas
-- Exemplo 1a:
-- O valor da comparação é feito em decimal e é utilizado uma comparação binária "&" para retonar o valor inteiro da função Columns_Updated()
-- O primeiro substring analisa as 8 primeiras colunas (1ª a 8ª) e depois as 8 próximas colunas (9ª a 16ª)

If ((Substring(Columns_Updated(),1,1) & 4) = 4) And 
    (Substring(Columns_Updated(),2,1) & 1) = 1))    
   Print 'Colunas 3 e 9'
   
-- Exemplo 2a:

If ((Substring(Columns_Updated(),1,1) & 160) = 160) And 
    (Substring(Columns_Updated(),2,1) & 21) = 21))      
   Print 'Colunas 6, 8, 9, 11 e 13 foram alteradas'
   
-- Exemplo 3a:
-- ao invés de utilizar um número decimal, é possível fazer o cálculo através da função power(2, pos_coluna-1)

If ((Substring(Columns_Updated(),1,1) & (power(2, 6-1) + power(2, 8-1)) ) = power(2, 6-1) + power(2, 8-1)) And 
    (Substring(Columns_Updated(),2,1) & power(2, 1-1) + power(2, 3-1) + power(2, 5-1) ) = power(2, 1-1) + power(2, 3-1) + power(2, 5-1)))
   Print 'Colunas 6, 8, 9, 11 e 13 foram alteradas'   
   
-- Exemplo 4: OR (para tabelas com até 8 colunas)
-- é possível validar através do "OU" binário "|"
-- valida se somente as colunas 6 ou 8 foram alterados

If (Columns_Updated() | 160) = 160
   Print 'Colunas 6 ou 8 foram alteradas'
   
-- Exemplo 5: XOR (para tabelas com até 8 colunas)
-- é possível validar através do "OU Exclusivo" binário "^"
-- valida se as colunas 6 ou 8 não foram alterados

If (Columns_Updated() ^ 160) = 160
   Print 'Colunas 6 ou 8 não foram alteradas'


Fim, ufa :)

0 comentários:

Postar um comentário