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 :)

Shell Script - Criação de um script de Backup com o p7zip ou 7za e compactar somente as subpastas de um diretório.

|

Para realizar um script de backup com a utilização do p7zip ou 7zip, é necessário informar o caminho onde fica o bin do 7zip "/usr/local/bin/7za" pois se utilizar somente o comando "7za" no script, não irá funcionar utilizando o cron para iniciar o script. Portanto para utilizar o p7zip no cron do linux é necessário passar todo o caminho do bin (7za).
Para realizar o backup por de um diretório e compactando somente as subpastas, utilizei o script abaixo.

#!/bin/sh
# Para melhor visualização do script irei colocar variáveis no script.
# Para informar que é uma viável é só colocar um $ antes da variável.
# Para exempĺo irei realizar a compactação da pasta /root e irei colocar os arquivos de backup em /BKP.


##### Setando as variáveis
# Arquivos de backup.
BKP_PASTA=/BKP/

# Temporário para ler as pastas do diretório.
TMP=/BKP/txt.tmp

# Setando a variável "x" para 1 (Esse onde ele começa a pegar a linha)
x=1

# Captura o número de pastas. (no caso no /root/) 
N_PASTAS=$(ls -d /root/*/ |wc -l)


### Inicio do Script
cd /root
# Captura as pastas do diretório (no caso o /root)
ls -d * > $TMP

# Utilizo o while para ele percorrer as linhas da variável TMP para realizar o backup das pastas
while [ $x -le $N_PASTAS ];
do

# Neste ponto ele lê a linha onde a variável "x" onde está apontado
L_TMP=$(cat $TMP | head -n $x | tail -n 1);

# Realiza o processo de compactação com o 7za
# Como dito, para a utilização do p7zip ou 7za deve-de fazer da forma abaixo
# Neste ponto ele faz a compactação e joga para o diretório de Backup definido anteriormente e compacta a pasta onde o "x" está apontando.
/usr/local/bin/7za a -sfx -m0=lzma -mx=9 -mfb=64 -md=32m -ms=on tar -jcvf $BKP_PASTA$L_TMP.exe  /root/$L_TMP 

# Incrementa mais 1 no x, fazendo assim pulando para a pŕoxima linha.
x=$((x+1));
}

done; # Sai do While

##### FIM

IBM DB2 - Criando Tabela temporária a partir de um Select

|

Criando Tabela temporária a partir de um Select:

DECLARE GLOBAL TEMPORARY TABLE TAB_TEMP AS (SELECT NOME FROM TABELA) WITH NO DATA

OBS: com esta instrução não é retornado dados do select.

Criando uma tabela temporária a partir de um Select e inserindo os registros do Select:
DECLARE GLOBAL TEMPORARY TABLE TAB_TEMP AS (SELECT * FROM TABELA) DEFINITION ONLY ON COMMIT PRESERVE ROWS;
INSERT INTO SESSION.TAB_TEMP SELECT * FROM TABELA;

IBM DB2 - Criando tabela temporária

|

O comando SQL abaixo demonstra como criar uma tabela temporária no banco de dados IBM DB2:

DECLARE GLOBAL TEMPORARY TABLE TEMP_EMP
   (EMPNO CHAR(6) NOT NULL,
    NOME VARCHAR(12) NOT NULL,
    ATIVO CHAR(1) NOT NULL,
    RAMO VARCHAR(15) NOT NULL,
    DEPTO CHAR(3),
    FONE CHAR(4)
   );

Delphi - Impedir que abra duas instâncias da mesma aplicação

|

O código abaixo demonstra como impedir que seja aberto duas instâncias da aplicação Delphi. Essa consistência deve ser colocada na unit do projeto(.dpr) de sua aplicação.

Var hd : THandle;
Begin
   hd := FindWindow('TApplication', 'NomeDaAplicação'); // Localizando janela de acordo com o nome da aplicação
   If hd = 0 Then // Verificando se a aplicação com o nome passado acima já esta aberto.
   Begin
      Application.Title := 'NomeDaAplicação'; // Definindo um nome para aplicação
      Application.Initialize;
      Application.CreateForm(TForm1, Form1);
      Application.Run;
   End;
End.

C# - Colorir linha do DataGridView

|

O trecho de código abaixo demonstra de forma simples como colorir um linha do DataGridView utilizando o evento RowPrePaint.

private void DataGridView_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
   DataGridView dgv = sender as DataGridView;
   /* Pegando valor de uma celula do DataGridView */
   string valor = dgv.Rows[e.RowIndex].Cells[1].Value.ToString();
   if (/*Sua Condição. Ex: valor = 1 */)
   {
      /* Alterando cor do Fundo */
      dgv.CurrentRow.DefaultCellStyle.BackColor = Color.Blue;
      /* Alterando cor da fonte */
      dgv.Rows[e.RowIndex].DefaultCellStyle.ForeColor = Color.Red;
   }
}

Delphi - Parâmetros de Valor Default

|

Para declarar um procedimento ou função que contém parâmetros de valor default, siga o tipo do parâmetro com um sinal de igual e o valor default como mostrado no exemplo seguinte:
procedure FuncaoComValorDefault(Str: string; I: Integer = 0);

O procedimento FuncaoComValorDefault() pode ser chamado de uma das formas. Primeiro, você pode chamar especificando os dois parâmetros:
FuncaoComValorDefault('Passando valor', 26);

Segundo, você pode especificar apenas o parâmetro S e usar o valor default para I:
FuncaoComValorDefault('Usando valor default'); //Neste caso é usado o valor default 0 para I

Você deve seguir várias regras quando usar parâmetros de valor default:
  1. Parâmetro que tem valor default devem aparecer no fim da lista de parâmetros. Parâmetros sem valores default não podem seguir parâmetros com valores default em uma lista de parâmetros de uma função ou procedimento.
  2. Parâmetros de valor default devem ser de um tipo ordinal, ponteiro ou set.
  3. Parâmetros de valor default devem ser passados por valor ou como constante. Eles não devem ser parâmetros de referência, out ou sem tipo.

Um dos maiores benefícios dos parâmetros de valor default é adicionar funcionalidade a funções e procedimentos existentes sem sacrificar compatibilidades anteriores, ou seja, se você já estiver utilizando a função em alguma parte do seu código e precisar adicionar um novo parâmetro que será utilizado somente por uma rotina especifica em outra parte código, o parâmetro com valor default irá livra-lo do retrabalho de alterar todas as chamadas a esta função.