Arquivo de julho, 2014

For – Looping – Ruby – Linux

Publicado: 25 de julho de 2014 em Ruby on Rails

Usando um loop for, você pode executar uma instrução ou um bloco de instruções repetidamente até que uma expressão especificada seja avaliada como falsa. Este tipo de circuito é útil para iterar sobre matrizes e para outras aplicações em que você sabe de antemão quantas vezes você quer iterar o loop.

For - Ruby - Console

For – Ruby – Console

Exemplo:

Neste exemplo utilizamos um For para iterar uma faixa de valores e utilizamos seu laço para criar uma simples tabuada.

Ruby

# Desenvolvimento Aberto
# Numeros.rb
 
# Coleta um numero
puts "Digite um numero para a tabuada: "
nu = gets
 
# Converte para inteiro
numero = nu.to_i
 
# Cria um laço com o numero escolhido
for n in 1..10
  puts n.to_s + " x " + numero.to_s + " = " + String(n * numero)
end
Publicidade

While – Looping – Ruby – Linux

Publicado: 24 de julho de 2014 em Ruby on Rails

O comando while executa uma instrução ou um bloco de instruções até que uma expressão especificada seja avaliada como falsa. Como o teste da expressão ocorre antes de cada execução do loop, um loop while executa nenhuma ou mais vezes. Isso difere do loop Do, que executa uma ou mais vezes. Veja este exemplo na figura abaixo:

While - Ruby - Console

While – Ruby – Console

Ruby não possui a instrução Do em sua coleção de comando de laços, e sim para marcar blocos de instruções, então para que o comando While tenha o efeito do comando Do (em outras linguagens de programação) você pode mudar a condição para o final do bloco de instruções iniciados com a palavra chave Begin.

Sintaxe:

begin
Bloco de comandos
end while (condição)

Deste modo o comando While executa pelo menos uma vez o bloco de instruções  independente da condição.

Exemplo:

Através de um laço diferenciamos os números impares e pares os exibindo no console, atente-se para a logica do comando While que executa nenhuma ou mais vezes pois o teste sempre ocorre antes da execução do loop.

Ruby

# Desenvolvimento Aberto
# pares.rb

# Coleta um numero
puts"Digite um numero limite:"
n = gets

# Converte para inteiro
numero = n.to_i

#Cria numeros iniciais pares e impares
npar = 0
nimpar = 1

# Cria um laço com o numero escolhido
while (npar <= numero)
  puts "numeros pares:" + npar.to_s + "     " + "numeros impares:" + nimpar.to_s
  npar = npar + 2
  nimpar = nimpar +2
end

 

IF é um dos comandos mais comuns e um dos mais importantes na programação, este comando é responsável pelas tomadas de decisões, existe praticamente em todas as linguagens de programação, antigamente este comando era conhecido como “se-então-senão” ou “if-then-else” mas as linguagens mais modernas substituirão o “então” pelo símbolo “{}” (colchetes), se a condição puder ser executada por apenas uma linha de comando então não é necessário usar o colchete.

Em Ruby a condição IF tem uma sintaxe um pouco diferente ficando assim:

IF(se) a condição for atendida faça algo, ELSIF (senão, se) outra condição for atendida faça algo, ELSE (senão) faça algo, END (fim da condição).

Looping - Ruby - Console

Looping – Ruby – Console

Exemplo:

Imagine o seguinte cenário:  nossos colaboradores estão autorizados a fazer um tipo de empréstimos na folha de pagamento, mas o empréstimo é habilitado apenas se o ganho mensal com desconto não ultrapassar R$ 1000,00. Porem temos um limite de R$ 10,00 para mais ou para menos que o gerente de sua respectiva área pode liberar. Assim devemos verificar o valor do salario e exibir uma mensagem referente ao empréstimo.

Ruby

# Desenvolvimento Aberto
# looping.rb

# Cria e alimenta variaveis
codigo = 10
nome = "Alberto da Silva"
ativo = true
salario = 1556.00

#Usando mascaras e convertendo
#imprime as variaveis usando mascaras
puts "Codigo:  valor int:    " + codigo.to_s
puts "Nome:    valor strig:  " + nome
puts "Ativo:   valor boolean: " + ativo.to_s
puts "Salario: valor float:   " + salario.to_s

#Coleta valor do desconto
puts "\nDigite o valor do desconto:"
desconto = gets

#Calcula e converte desconto
salario = salario - desconto.to_f

#Imprime o resultado
puts "Valor do salario liquido: " + salario.to_s

# Decide o emprestimo
if (salario >= 1010)
  puts "\nEmprestimo desabilitado"
elsif  (salario >=990) and (salario <=1010)
  puts "\nFale com o Gerente"
else
  puts "\nEmprestimo habilitado"
end

O método gets nos possibilita questionar o usuário, criando um prompt para entrada de dados, assim que o usuário entrar com os dados e pressionar a tecla Enter, o programa retoma seu funcionamento armazenando os dados inseridos em uma variável de formato String.

Sendo o Ruby uma linguagem OO pura podemos utilizar as próprias variáveis que também são objetos para converter os valores de tipos diferentes para que possamos manipula-las da maneira correta, assim transformarmos por exemplo: strings para floats, afim de calcularmos algum valor e retornar o objeto para o formato string assim para que ele possa ser impresso no console.

Console - Ruby

Console – Ruby

Exemplo:

Neste exemplo criamos um cadastro fictício com objetos de tipos diferentes e os convertemos para efetuarmos um calculo com a entrada de dados do usuário para o valor do desconto que conseguimos através do método gets.

Ruby

# Desenvolvimento Aberto
# entrada.rb
 
# Cria e alimenta variaveis
codigo = 10
nome = "Alberto da Silva"
ativo = true
salario = 1556.00
 
#Usando mascaras e convertendo
#imprime as variaveis usando mascaras
puts "Codigo:  valor int:    " + codigo.to_s
puts "Nome:    valor strig:  " + nome
puts "Ativo:   valor boolean: " + ativo.to_s
puts "Salario: valor float:   " + salario.to_s
 
#Coleta valor do desconto
puts "\nDigite o valor do desconto:"
desconto = gets
 
#Calcula e converte desconto
salario = salario - desconto.to_f
 
#Imprime o resultado
puts "Valor do salario liquido: " + salario.to_s

A linguagem de programação Ruby é uma linguagem puramente orientada a objetos (pure object-oriented), o que significa que tudo em Ruby é um objeto. Isso mesmo, tudo! Se por outro lado, linguagens como C++ e Java são linguagens híbridas que dividem o mundo entre objetos e tipos primitivos. A abordagem híbrida resulta em melhor desempenho para algumas aplicações, mas a abordagem orientada a objetos pura é mais consistente e simples de usar.

Isso quer dizer que um numero inteiro em Java ou C++ é um tipo primitivo e não um objeto, em Ruby um numero inteiro é um objeto, por exemplo, caso você queira converter um numero inteiro literal (sem associação a uma variável) em uma String, simples, o numero também é um objeto e você converte-lo usando o método to string, assim : 1.to_s e este objeto será equivalente a “1”.

Objetos – Variáveis em Ruby

1 -Vamos criar um projeto Ruby utilizando a IDE Aptana Studio 3, clique em File e New Project e nomeie o projeto de Variáveis:

Novo Projeto

Novo Projeto

2 – Após criar o projeto, clique com o botão direito do mouse em cima do seu projeto, na arvore App Explore e escolha New File e nomeie o arquivo como var.rb:

Arquivo Ruby

Arquivo Ruby

3 -Digite o código abaixo e clique em Run para executar o programa:

Console Ruby

Console Ruby

Exemplo:

Neste exemplo criamos um programa Ruby utilizando os tipos básicos como Integer, Double, Strings e Boolean, utilizamos o objeto String() para converter os outros tipos para string para serem impressos na tela, utilizamos também o próprio objeto e seu método to_s para converter a variável para String já que tudo em Ruby é um objeto.

Ruby

# Cria Variáveis
# Em Ruby tudo é um Objeto

id = 1
codigo = 12533
nome = "Mario Luis da Silva"
cargo = "Analista de Sistemas"
salario = 3523.87
ativo = true

# Imprime as variáveis como string
# Visto que precisamos converte-las
# Utilizamos o método String()
# E o método do próprio objeto to_s

puts " ***** Cadastro de Funcionarios *****"
puts ""
puts "Id: " + String(id)
puts "Cod: " + codigo.to_s
puts "Nome: " + nome
puts "Cargo: " + cargo
puts "Salario: " + String(salario)
puts "Ativo: " + ativo.to_s

Database – Triggers – Oracle – Python

Publicado: 20 de julho de 2014 em Python

Uma Trigger ou gatilho é um tipo especial de procedimento armazenado (Stored Procedure) que executa automaticamente quando um evento ocorre no servidor de banco de dados. Gatilhos DML executam quando um usuário tenta modificar dados através de uma linguagem de manipulação de dados (DML). Eventos DML são INSERT, UPDATE, ou DELETE em uma tabela ou exibição. Esses gatilhos disparam quando qualquer evento válido é acionado, independentemente de haver ou não linhas da tabela afetadas.

As Triggers possuem muitas diferenças de sintaxe e funcionalidades de um banco de dados para outro, por exemplo Trigger que dispara o evento INSTEAD OF INSERT (ao invés de inserir) no banco de dados Oracle só pode ser declarada sobre uma VIEW enquanto em MSSQL Server pode ser declarada em uma tabela comum, o evento BEFORE INSERT (antes de inserir) existe nos bancos de dados Oracle e IBM DB2, mas não existe no MSSQL. Por este motivo é recomendado que você procure os links oficiais para saber mais detalhes sobre as Triggers.

Trigger - Python - Oracle

Trigger – Python – Oracle

Algo extremamente útil sobre Triggers

As Triggers foram regulamentadas na revisão da língua SQL em 1999 e passou a ser padrão em banco de dados relacionais, no entanto alguns bancos de dados vem atualizando estes recursos regularmente, por exemplo o Oracle utiliza Triggers que disparam por esquema (Schema-level triggers) desde a sua versão 9i, enquanto o MSSQL suporta trigger do tipo DDL, ou logon trigger apenas desde a versão 2008.

Muitos sistemas de grande porte como SAP e vários outros não utilizam triggers, principalmente sistemas que no qual rodam em diversos bancos de dados, estas são consideradas verdadeiras armadilhas por muitos DBAs, podem ser facilmente esquecidas na hora de alterações e se tornarem invalidas (Oracle), gerando assim muitos erros caso não haja uma boa politica de desenvolvimento e qualidade (testes unitários e integrados) antes de colocar as rotinas do sistema em produção. Mesmo as IDEs de estudios SQL já mudaram varias vezes a localização do node de triggers ao longo de suas versões para tentar facilitar a manutenção das mesmas.

As Triggers também devem ser desenvolvidas com cuidado sempre seguindo as melhores praticas, pois o desenvolvimento SQL é muito abrangentes e cheio de recursos, então é fácil extrapolar e criar triggers contendo cursores, stored procedures, rollbacks, acessos repetitivos, outras triggers, lembre-se da lei de Murphy, tudo que não pode ser escrito em uma trigger, será e isto reduz sensivelmente a performance de um sistema, sem contar com a complexidade do desenvolvimento, transformado seu desenvolvimento SQL em verdadeiros planos da ACME, lembre-se do coite que tentava incessantemente capturar o papa-léguas.

Cuidado com as Triggers

Cuidado com as Triggers

Nunca use Triggers para criar campos auto incremento para os códigos (ID), os bancos de dados possuem recursos específicos para este trabalho, o uso de triggers somente criará acessos e UPDATES desnecessários no banco de dados, além de reduzir a performance, imagine importar 10.000 linhas utilizando um Insert…Select, à partir de uma outra tabela ou arquivos externos, você efetuara um Select e um Update para cada registro se utilizar triggers, enquanto os bancos de dados contam com seus campos auto incremento que já nos permitem utilizar dados em massa e inserir as 10.000 linhas em um único acesso.

As Triggers também são um alto risco a segurança, é possível escalar privilégios e se tornar proprietário do banco de dados e do servidor SQL caso você insira um código mal intencionado em uma Trigger, exemplo: suponha que o usuário Jõao da Silva tenha diretos de Administrador do banco de dados,  se um desenvolvedor mal intencionado criar uma trigger DDL sobre o evento DELETE de uma tabela qualquer utilizando por exemplo a instrução: GRANT CONTROL SERVER TO BadUser; Quando o usuário João da Silva executar o procedimento que dispara a trigger o Grant será delegado ao usuário mal intencionado e os direitos aplicados a ele, enquanto ele mesmo não teria acesso para delegar tal direito, deste modo possibilitando que o desenvolvedor mal intencionado tome conta do servidor SQL, podendo fazer o que bem entender com os dados.

Security: http://msdn.microsoft.com/pt-br/library/ms191134.aspx

Exemplo:

Neste exemplo criamos uma funcionalidade similar do nosso exemplo anterior (Cursor), utilizando a mesma modelagem de dados, porem para executar este procedimento as tabelas DESCONTO e SALARIO devem estar vazias, o usuário entrará com o código do funcionário e a porcentagem do desconto e a trigger sobre a tabela DESCONTO se encarregara de criar o lançamento na tabela de SALARIO.

SQL

Oracle

create table Funcionarios(
  ID_Funcionario  NUMBER(5),
  Nome            VARCHAR2(30),
  Sobrenome       VARCHAR2(70),
  Cargo           VARCHAR2(30),
  Salario         NUMBER(9,2));

-- Cria Funcionarios
Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);
Insert into FUNCIONARIOS values (3,'Wozniak','Gates','Desenvolvedor', 4389.21);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO NUMBER,
  PORCENTAGEM NUMBER(9,2));

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO NUMBER,
  DATA_LANC  DATE,
  VDESCONTO NUMBER(9,2));

-- Deleta dados antigos
-- Caso utlizou exemplos anteriores
delete from desconto;
delete from salario;

-- Cria trigger na tabela Desconto
create or replace TRIGGER DESCONTO_INSERT
   BEFORE INSERT ON DESCONTO
   FOR EACH ROW

   -- Declara variáveis
   DECLARE pID NUMBER;
           pSalario NUMBER(9,2);
           pPorcentagem NUMBER(9,2);
   BEGIN   

    -- Alimenta variáveis com os valores a serem inseridos
    pID := :new.ID_FUNCIONARIO;
    pPorcentagem := :new.PORCENTAGEM;

    -- Seleciona Salario do funcionario corrente
    Select SALARIO INTO pSalario FROM FUNCIONARIOS
    WHERE ID_FUNCIONARIO = pID;

    -- insere na tabela de lançamentos de salario
    Insert into SALARIO
     values (
             pID,
             SYSDATE,
             (pSalario * pPorcentagem)/100);

   END DESCONTO_INSERT;

Python

#!/usr/bin/env python
# -*- coding: latin-1 -*-
# Desenvolvimento Aberto
# TriggerOracle.py
 
# importa modulos
import wx
import wx.grid
import cx_Oracle
 
# Cria classe generica de uma WX.Grid
# A classe abaixo faz parte da documentação WXPython oficial
# Este trecho de código é util para manipular a grade
 
class GenericTable(wx.grid.PyGridTableBase):
    def __init__(self, data, rowLabels=None, colLabels=None):
        wx.grid.PyGridTableBase.__init__(self)
        self.data = data
        self.rowLabels = rowLabels
        self.colLabels = colLabels
 
    def GetNumberRows(self):
        return len(self.data)
 
    def GetNumberCols(self):
        return len(self.data[0])
 
    def GetColLabelValue(self, col):
        if self.colLabels:
            return self.colLabels[col]
 
    def GetRowLabelValue(self, row):
        if self.rowLabels:
            return self.rowLabels[row]
 
    def IsEmptyCell(self, row, col):
        return False
 
    def GetValue(self, row, col):
        return self.data[row][col]
 
    def SetValue(self, row, col, value):
        pass     


# Inicializa Grade
dados = []
colLabels  = []
rowLabels = ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10")

# Cria conexão
def conectarORA():
    sconexao = "user/password@localhost/XE"
    try:
       con = cx_Oracle.connect(sconexao)
    except ValueError:
       tkMessageBox.showinfo(title="Menssagem", message="Erro de Conexão", parent=janela)
    return con

# Executa e retorna SQL
def retornaTabelaORA(sql, con):
     cursor = con.cursor()
     cursor.execute(sql)
     return cursor
        
def retornaDados(idfunc):
    # Cria conexão
    con = conectarORA()    
    # Envia dados a grid
    sql = "Select A.ID_FUNCIONARIO, " + "A.NOME, " + " A.CARGO, " + \
          " A.SALARIO, " + "B.PORCENTAGEM, " + "C.VDESCONTO, " + \
          "C.DATA_LANC,  " + "A.SALARIO - C.VDESCONTO AS SLIQUIDO " +\
          "from FUNCIONARIOS A, DESCONTO B, SALARIO C " + "Where " + \
          "A.ID_FUNCIONARIO = B.ID_FUNCIONARIO  AND " + \
          "A.ID_FUNCIONARIO = C.ID_FUNCIONARIO  AND " + \
          "A.ID_FUNCIONARIO = " + idfunc
    # retorna set de dados
    tabela = retornaTabelaORA(sql, con)

    # Retorna metadados da tabela
    for i in range(0, len(tabela.description)):
        colLabels.append(tabela.description[i][0])

    # Executa um fecth em todos os registros
    resultado = tabela.fetchall()

    # Popula dados
    for conteudo in resultado:
        dados.append(conteudo)

             

# Cria classe da grid
class SimpleGrid(wx.grid.Grid):
    def __init__(self, parent):
        wx.grid.Grid.__init__(self, parent, -1, pos=(5,90), size=(850,200))    
                         
 
# Cria formulario
class TestFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, "Desenvolvimento Aberto - Triggers - Python", size=(900, 350))
        panel        = wx.Panel(self, wx.ID_ANY)
        label        = wx.StaticText(panel, -1, label='Oracle Database - Triggers ->', pos=(300,10))
        lfuncionario = wx.StaticText(panel, -1, label='Cod funcionario:', pos=(20,50))
        self.funcionario  = wx.TextCtrl(panel, size=(100, -1), pos=(120,50))
        lporcentagem = wx.StaticText(panel, -1, label='Porcentagem (%):', pos=(260,50))
        self.porcentagem  = wx.TextCtrl(panel, size=(100, -1), pos=(360,50))
        botao        =   wx.Button(panel, label="Inserir", pos=(480,50))
        botao.Bind(wx.EVT_BUTTON, self.botaoInserir)
        self.grid         = SimpleGrid(panel)

    #Insere dados e dispara trigger
    def botaoInserir(self,event):
        # Conecta e cria um cursor
        con = conectarORA()        
        cursor = con.cursor()
        # Insere clausula SQL
        sql = "insert into DESCONTO VALUES (" + self.funcionario.GetValue() + ", " + self.porcentagem.GetValue() + ")";
        # Executa e comita a transação
        cursor.execute(sql)
        con.commit()
        # Retorna set de dados
        retornaDados(self.funcionario.GetValue())
        # Limpa grade
        self.grid.ClearGrid()
        # Insere set de dados contidos em um tuplas
        tableBase = GenericTable(dados, rowLabels, colLabels)
        self.grid.SetTable(tableBase)
        # Atualiza grade
        self.grid.ForceRefresh()
        
        
# Inicializa a aplicação
app = wx.PySimpleApp()
frame = TestFrame(None)
frame.Show(True)
app.MainLoop()

Uma Trigger ou gatilho é um tipo especial de procedimento armazenado (Stored Procedure) que executa automaticamente quando um evento ocorre no servidor de banco de dados. Gatilhos DML executam quando um usuário tenta modificar dados através de uma linguagem de manipulação de dados (DML). Eventos DML são INSERT, UPDATE, ou DELETE em uma tabela ou exibição. Esses gatilhos disparam quando qualquer evento válido é acionado, independentemente de haver ou não linhas da tabela afetadas.

As Triggers possuem muitas diferenças de sintaxe e funcionalidades de um banco de dados para outro, por exemplo Trigger que dispara o evento INSTEAD OF INSERT (ao invés de inserir) no banco de dados Oracle só pode ser declarada sobre uma VIEW enquanto em MSSQL Server pode ser declarada em uma tabela comum, o evento BEFORE INSERT (antes de inserir) existe nos bancos de dados Oracle e IBM DB2, mas não existe no MSSQL. Por este motivo é recomendado que você procure os links oficiais para saber mais detalhes sobre as Triggers.

Triggers - C++

Triggers – C++

Algo extremamente útil que você deve saber sobre Triggers

As Triggers foram regulamentadas na revisão da língua SQL em 1999 e passou a ser padrão em banco de dados relacionais, no entanto alguns bancos de dados vem atualizando estes recursos regularmente, por exemplo o Oracle utiliza Triggers que disparam por esquema (Schema-level triggers) desde a sua versão 9i, enquanto o MSSQL suporta trigger do tipo DDL, ou logon trigger apenas desde a versão 2008.

Muitos sistemas de grande porte como SAP e vários outros não utilizam triggers, principalmente sistemas que no qual rodam em diversos bancos de dados, estas são consideradas verdadeiras armadilhas por muitos DBAs, podem ser facilmente esquecidas na hora de alterações e se tornarem invalidas (Oracle), gerando assim muitos erros caso não haja uma boa politica de desenvolvimento e qualidade (testes unitários e integrados) antes de colocar as rotinas do sistema em produção. Mesmo as IDEs de estudios SQL já mudaram varias vezes a localização do node de triggers ao longo de suas versões para tentar facilitar a manutenção das mesmas, aqui veremos como exemplo a IDE do IBM Data Studio que possui um wizard especifico para triggers.

As Triggers também devem ser desenvolvidas com cuidado sempre seguindo as melhores praticas, pois o desenvolvimento SQL é muito abrangentes e cheio de recursos, então é fácil extrapolar e criar triggers contendo cursores, stored procedures, rollbacks, acessos repetitivos, outras triggers, lembre-se da lei de Murphy, tudo que não pode ser escrito em uma trigger, será e isto reduz sensivelmente a performance de um sistema, sem contar com a complexidade do desenvolvimento, transformado seu desenvolvimento SQL em verdadeiros planos da ACME, lembre-se do coite que tentava incessantemente capturar o papa-léguas.

Cuidado com as Triggers

Cuidado com as Triggers

Nunca use Triggers para criar campos auto incremento para os códigos (ID), os bancos de dados possuem recursos específicos para este trabalho, o uso de triggers somente criará acessos e UPDATES desnecessários no banco de dados, além de reduzir a performance, imagine importar 10.000 linhas utilizando um Insert…Select, à partir de uma outra tabela ou arquivos externos, você efetuara um Select e um Update para cada registro se utilizar triggers, enquanto os bancos de dados contam com seus campos auto incremento que já nos permitem utilizar dados em massa e inserir as 10.000 linhas em um único acesso.

As Triggers também são um alto risco a segurança, é possível escalar privilégios e se tornar proprietário do banco de dados e do servidor SQL caso você insira um código mal intencionado em uma Trigger, exemplo: suponha que o usuário Jõao da Silva tenha diretos de Administrador do banco de dados,  se um desenvolvedor mal intencionado criar uma trigger DDL sobre o evento DELETE de uma tabela qualquer utilizando por exemplo a instrução: GRANT CONTROL SERVER TO BadUser; Quando o usuário João da Silva executar o procedimento que dispara a trigger o Grant será delegado ao usuário mal intencionado e os direitos aplicados a ele, enquanto ele mesmo não teria acesso para delegar tal direito, deste modo possibilitando que o desenvolvedor mal intencionado tome conta do servidor SQL, podendo fazer o que bem entender com os dados.

Security: http://msdn.microsoft.com/pt-br/library/ms191134.aspx

Visual Studio

Para efetuar as conexões com os diferentes bancos de dados você precisa primeiro configurar os drivers ODBC necessários no sistema operacional, depois você pode criar um design com 3 componentes RadioButton, 2 componentes Static Texts, 2 componentes Text Control, um componente Button e um componente CListControl,  você encontra um walkthrough de como configurar os drivers ODBC na categoria SQL e C++ deste site, use a figura abaixo para referencia do design:

C++ - Design Time

C++ – Design Time

IBM Data Studio

O IBM Data Studio possui uma funcionalidade especifica para criar triggers (Wizard), assim como possui para Stored Procedures e Function no qual necessitam de executar um Deploy antes de ser executada. Portanto você não poderá criar a Trigger utilizando a configuração Default do editor SQL comum, para isto você precisa mudar a configuração do terminador de instrução de ponto e virgula (;) para arroba(@), basta clicar com o botão direito do mouse e escolher a opção: Configurar Terminador de Instrução. Utilize a figura abaixo para referencia:

IBM Data Studio - Configuração

IBM Data Studio – Configuração

Exemplo:

Neste exemplo criamos uma funcionalidade similar do nosso exemplo anterior (Cursor), utilizando a mesma modelagem de dados, porem para executar este procedimento as tabelas DESCONTO e SALARIO devem estar vazias, o usuário entrará com o código do funcionário e a porcentagem do desconto e a trigger sobre a tabela DESCONTO se encarregara de criar o lançamento na tabela de SALARIO.

SQL

Oracle

create table Funcionarios(
  ID_Funcionario  NUMBER(5),
  Nome            VARCHAR2(30),
  Sobrenome       VARCHAR2(70),
  Cargo           VARCHAR2(30),
  Salario         NUMBER(9,2));

-- Cria Funcionarios
Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);
Insert into FUNCIONARIOS values (3,'Wozniak','Gates','Desenvolvedor', 4389.21);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO NUMBER,
  PORCENTAGEM NUMBER(9,2));

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO NUMBER,
  DATA_LANC  DATE,
  VDESCONTO NUMBER(9,2));

-- Deleta dados antigos
-- Caso utlizou exemplos anteriores
delete from desconto;
delete from salario;

-- Cria trigger na tabela Desconto
create or replace TRIGGER DESCONTO_INSERT
   BEFORE INSERT ON DESCONTO
   FOR EACH ROW

   -- Declara variáveis
   DECLARE pID NUMBER;
           pSalario NUMBER(9,2);
           pPorcentagem NUMBER(9,2);
   BEGIN   

    -- Alimenta variáveis com os valores a serem inseridos
    pID := :new.ID_FUNCIONARIO;
    pPorcentagem := :new.PORCENTAGEM;

    -- Seleciona Salario do funcionario corrente
    Select SALARIO INTO pSalario FROM FUNCIONARIOS
    WHERE ID_FUNCIONARIO = pID;

    -- insere na tabela de lançamentos de salario
    Insert into SALARIO
     values (
             pID,
             SYSDATE,
             (pSalario * pPorcentagem)/100);

   END DESCONTO_INSERT;

DB2

create table Funcionarios (
    ID_Funcionario  INTEGER,
    Nome            VARCHAR(30),
    Sobrenome       VARCHAR(70),
    Cargo           VARCHAR(30),
    Salario         NUMERIC(9,2))@

Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56)@
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71)@
Insert into FUNCIONARIOS values (3,'Wozniak','Gates','Desenvolvedor', 4389.21)@

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INTEGER,
  PORCENTAGEM DECIMAL(9,2))@

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO INTEGER,
  DATA_LANC  DATE,
  VDESCONTO DECIMAL(9,2))@

-- Deleta dados antigos
-- Caso utlizou exemplos anteriores
delete from desconto@
delete from salario@

-- Cria trigger na tabela Desconto
create TRIGGER DESCONTO_INSERT
   BEFORE INSERT ON DESCONTO
   REFERENCING NEW AS N
   FOR EACH ROW

 P1:  BEGIN

   -- Declara variáveis
   DECLARE pID NUMBER;
   DECLARE pSalario DECIMAL(9,2);
   DECLARE pPorcentagem DECIMAL(9,2);

    -- Alimenta variáveis com os valores a serem inseridos
    SET pID = N.ID_FUNCIONARIO;
    SET pPorcentagem = N.PORCENTAGEM;

    -- Seleciona Salario do funcionario corrente
    Select SALARIO INTO pSalario FROM FUNCIONARIOS
    WHERE ID_FUNCIONARIO = pID;

    -- insere na tabela de lançamentos de salario
    Insert into SALARIO
     values (
             pID,
             SYSDATE,
             (pSalario * pPorcentagem)/100);

   END P1

MSSQL

create table Funcionarios (
   ID_Funcionario  Int,
   Nome            VARCHAR(30),
   Sobrenome       VARCHAR(70),
   Cargo           VARCHAR(30),
   Salario         Decimal(9,2));

Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);
Insert into FUNCIONARIOS values (3,'Wozniak','Gates','Desenvolvedor', 4389.21);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INT,
  PORCENTAGEM DECIMAL(9,2));

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO INT,
  DATA_LANC  DATE,
  VDESCONTO DECIMAL(9,2));

-- Deleta dados antigos
-- Caso utlizou exemplos anteriores
delete from desconto;
delete from salario;

-- Cria trigger na tabela Desconto
create TRIGGER DESCONTO_INSERT ON
  DESCONTO AFTER INSERT AS      

   BEGIN
   -- Declara variáveis
   DECLARE @pID Int,
           @pSalario DECIMAL(9,2),
           @pPorcentagem DECIMAL(9,2); 

    -- Alimenta variáveis com os valores a serem inseridos
	Select @pID = ID_FUNCIONARIO,
	       @pPorcentagem = PORCENTAGEM
    from inserted;

    -- Seleciona Salario do funcionario corrente
    Select  @pSalario = SALARIO FROM FUNCIONARIOS
    WHERE ID_FUNCIONARIO = @pID;

    -- insere na tabela de lançamentos de salario
    Insert into SALARIO
     values (
             @pID,
             GETDATE(),
             (@pSalario * @pPorcentagem)/100);

   END;

C++

Classe – AcessocppDlg.h

// Classe gerada automaticamente
// AcessocppDlg.h : header file
//

#pragma once

// Inclui classe de banco de dados MFC
#include "afxdb.h"
#include "afxcmn.h"
#include "afxwin.h"

class CAcessocppDlg : public CDialogEx
{

public:
	CAcessocppDlg(CWnd* pParent = NULL);	// standard constructor

	enum { IDD = IDD_ACESSOCPP_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support

protected:
	HICON m_hIcon;

	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:

	// Cria métodos e objetos da classe
	CDatabase db;
	CString bancodedados;
	void conectarDB(CString dns, CString usuario, CString senha);

	afx_msg void OnBnHotItemChangeRadio1(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnHotItemChangeRadio2(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnHotItemChangeRadio3(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnClickedButton1();
	CListCtrl m_tabela;
	CEdit m_funcionario;
	CEdit m_porcentagem;
};

Classe – AcessocppDlg.cpp

// Código gerado automaticamente
// AcessocppDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Acessocpp.h"
#include "AcessocppDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);   

protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

CAcessocppDlg::CAcessocppDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CAcessocppDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CAcessocppDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST2, m_tabela);
	DDX_Control(pDX, IDC_EDIT1, m_funcionario);
	DDX_Control(pDX, IDC_EDIT2, m_porcentagem);
}

BEGIN_MESSAGE_MAP(CAcessocppDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_NOTIFY(BCN_HOTITEMCHANGE, IDC_RADIO1, &CAcessocppDlg::OnBnHotItemChangeRadio1)
	ON_NOTIFY(BCN_HOTITEMCHANGE, IDC_RADIO2, &CAcessocppDlg::OnBnHotItemChangeRadio2)
	ON_NOTIFY(BCN_HOTITEMCHANGE, IDC_RADIO3, &CAcessocppDlg::OnBnHotItemChangeRadio3)
	ON_BN_CLICKED(IDC_BUTTON1, &CAcessocppDlg::OnBnClickedButton1)
END_MESSAGE_MAP()

BOOL CAcessocppDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	SetIcon(m_hIcon, TRUE);
	SetIcon(m_hIcon, FALSE);		

	// Desenvolvimento Aberto
	// Inicializa dialogo

	// Define variavel padrão para o banco de dados
	bancodedados = "oracle";

	// Cria o modelo de exibição de dados
	m_tabela.SetView(LV_VIEW_DETAILS);
	m_tabela.SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_GRIDLINES);

	return TRUE;
}

void CAcessocppDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

void CAcessocppDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); 

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

HCURSOR CAcessocppDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

// **************************
// * Desenvolvimento Aberto *
// **************************
// Nosso código começa aqui

// Seleciona banco de dados Oracle
void CAcessocppDlg::OnBnHotItemChangeRadio1(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMBCHOTITEM pHotItem = reinterpret_cast<LPNMBCHOTITEM>(pNMHDR);

	bancodedados = "oracle";
	*pResult = 0;
}

// Seleciona banco de dados IBM DB2
void CAcessocppDlg::OnBnHotItemChangeRadio2(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMBCHOTITEM pHotItem = reinterpret_cast<LPNMBCHOTITEM>(pNMHDR);

	bancodedados = "db2";
	*pResult = 0;
}

// Seleciona banco de dados MSSQL
void CAcessocppDlg::OnBnHotItemChangeRadio3(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMBCHOTITEM pHotItem = reinterpret_cast<LPNMBCHOTITEM>(pNMHDR);

	bancodedados = "mssql";
	*pResult = 0;
}

// Evento de clique do botão
void CAcessocppDlg::OnBnClickedButton1()
{
	// campo de dado da tabela
	CString m_campo;

	// Abre conexão
	if (bancodedados == "oracle")
	{
		conectarDB(L"OracleXE", L"daberto", L"p@55w0rd");
	}

	if (bancodedados == "db2")
	{
		conectarDB(L"IBMDB2", L"db2admin", L"p@55w0rd");
	}

	if (bancodedados == "mssql")
	{
		conectarDB(L"MSSQLSERVER", L"devaberto", L"p@55w0rd");
	}

	// Cria um set de dados
	CRecordset  dados(&db);

	// Cria variáveis de entrada
	CString m_func;
	CString m_porc;

	// Recupera valor de entrada
	m_funcionario.GetWindowTextW(m_func);
	m_porcentagem.GetWindowTextW(m_porc);

	// Cria instrução SQL para disparar a trigger
	CString sqltrigger = L"insert into DESCONTO VALUES (" + m_func + ", " + m_porc + ")";

	// Executa instrução SQL
    db.ExecuteSQL(sqltrigger);

	CString sql = L"Select A.ID_FUNCIONARIO, A.NOME, A.CARGO, A.SALARIO, B.PORCENTAGEM, C.VDESCONTO, C.DATA_LANC, A.SALARIO - C.VDESCONTO AS SLIQUIDO from FUNCIONARIOS A, DESCONTO B, SALARIO C Where A.ID_FUNCIONARIO = B.ID_FUNCIONARIO  AND A.ID_FUNCIONARIO = C.ID_FUNCIONARIO";

	dados.Open(CRecordset::forwardOnly, sql);

	// Cria item
	LVITEM lvItem;

	// cria estrutura para inserir o item
	typedef struct _LVITEM
	{
		UINT mask;
		int iItem;
		int iSubItem;
		UINT state;
		UINT stateMask;
		LPTSTR pszText;
		int cchTextMax;
		int iImage;
		LPARAM lParam;
        #if (_WIN32_IE >= 0x0300)
		  int iIndent;
        #endif
	 } LVITEM, FAR *LPLVITEM;

	// Define variaveis de itens
	int InsertItem(const LVITEM* pItem);
	int nItem;

	// Converte CString para LPTSTR atraves de um TCHAR
	TCHAR sz[1024];

	// Verifica colunas
	short nFields = dados.GetODBCFieldCount();
	int colunas = m_tabela.GetHeaderCtrl()->GetItemCount();

	// Verifica colunas
	if (colunas == 0)
	{
		// Lê metadata da tabela
		CODBCFieldInfo field;
		for (UINT i = 0; i < nFields; i ++)
		{
			dados.GetODBCFieldInfo(i, field);
			m_tabela.InsertColumn(i, field.m_strName, LVCFMT_LEFT, 100);
		}

	}

	// Deleta itens do controle de lista
	m_tabela.DeleteAllItems();

	// Recupera dados da tabela
	while (!dados.IsEOF())
	{
		for (short index = 0; index < nFields; index++)
		{
			dados.GetFieldValue(index, m_campo);

			// Retorna linha do banco de dados
			if (index == 0)
			{
				// Insere linha
				lvItem.mask = LVIF_TEXT;
				lvItem.iItem = 0;
				lvItem.iSubItem = 0;
				lvItem.pszText = lstrcpy(sz, m_campo);
				nItem = m_tabela.InsertItem(&lvItem);
			}

			// Retorna colunas da linha
			m_tabela.SetItemText(nItem, index, lstrcpy(sz, m_campo));

		}
		// Move o cursor para a proxima linha
		dados.MoveNext();
	}

	// Fecha o set de dados e a conexão
	dados.Close();
	db.Close();

}

void CAcessocppDlg::conectarDB(CString dns, CString usuario, CString senha)
{
	// Cria string de conexão ODBC
	CString conexao;

	// Cria string de conexão
	conexao = L"DSN=" + dns + L";UID=" + usuario + L";PWD=" + senha;

	// Abre conexão
	db.OpenEx(conexao, 0);
}

Uma Trigger ou gatilho é um tipo especial de procedimento armazenado (Stored Procedure) que executa automaticamente quando um evento ocorre no servidor de banco de dados. Gatilhos DML executam quando um usuário tenta modificar dados através de uma linguagem de manipulação de dados (DML). Eventos DML são INSERT, UPDATE, ou DELETE em uma tabela ou exibição. Esses gatilhos disparam quando qualquer evento válido é acionado, independentemente de haver ou não linhas da tabela afetadas.

As Triggers possuem muitas diferenças de sintaxe e funcionalidades de um banco de dados para outro, por exemplo Trigger que dispara o evento INSTEAD OF INSERT (ao invés de inserir) no banco de dados Oracle só pode ser declarada sobre uma VIEW enquanto em MSSQL Server pode ser declarada em uma tabela comum, o evento BEFORE INSERT (antes de inserir) existe nos bancos de dados Oracle e IBM DB2, mas não existe no MSSQL. Por este motivo é recomendado que você procure os links oficiais para saber mais detalhes sobre as Triggers.

Triggers - C#

Triggers – C#

 

Algo extremamente útil que você deve saber sobre Triggers

As Triggers foram regulamentadas na revisão da língua SQL em 1999 e passou a ser padrão em banco de dados relacionais, no entanto alguns bancos de dados vem atualizando estes recursos regularmente, por exemplo o Oracle utiliza Triggers que disparam por esquema (Schema-level triggers) desde a sua versão 9i, enquanto o MSSQL suporta trigger do tipo DDL, ou logon trigger apenas desde a versão 2008.

Muitos sistemas de grande porte como SAP e vários outros não utilizam triggers, principalmente sistemas que no qual rodam em diversos bancos de dados, estas são consideradas verdadeiras armadilhas por muitos DBAs, podem ser facilmente esquecidas na hora de alterações e se tornarem invalidas (Oracle), gerando assim muitos erros caso não haja uma boa politica de desenvolvimento e qualidade (testes unitários e integrados) antes de colocar as rotinas do sistema em produção. Mesmo as IDEs de estudios SQL já mudaram varias vezes a localização do node de triggers ao longo de suas versões para tentar facilitar a manutenção das mesmas, aqui veremos como exemplo a IDE do IBM Data Studio que possui um wizard especifico para triggers.

As Triggers também devem ser desenvolvidas com cuidado sempre seguindo as melhores praticas, pois o desenvolvimento SQL é muito abrangentes e cheio de recursos, então é fácil extrapolar e criar triggers contendo cursores, stored procedures, rollbacks, acessos repetitivos, outras triggers, lembre-se da lei de Murphy, tudo que não pode ser escrito em uma trigger, será e isto reduz sensivelmente a performance de um sistema, sem contar com a complexidade do desenvolvimento, transformado seu desenvolvimento SQL em verdadeiros planos da ACME, lembre-se do coite que tentava incessantemente capturar o papa-léguas.

Cuidado com as Triggers

Cuidado com as Triggers

Nunca use Triggers para criar campos auto incremento para os códigos (ID), os bancos de dados possuem recursos específicos para este trabalho, o uso de triggers somente criará acessos e UPDATES desnecessários no banco de dados, além de reduzir a performance, imagine importar 10.000 linhas utilizando um Insert…Select, à partir de uma outra tabela ou arquivos externos, você efetuara um Select e um Update para cada registro se utilizar triggers, enquanto os bancos de dados contam com seus campos auto incremento que já nos permitem utilizar dados em massa e inserir as 10.000 linhas em um único acesso.

As Triggers também são um alto risco a segurança, é possível escalar privilégios e se tornar proprietário do banco de dados e do servidor SQL caso você insira um código mal intencionado em uma Trigger, exemplo: suponha que o usuário Jõao da Silva tenha diretos de Administrador do banco de dados,  se um desenvolvedor mal intencionado criar uma trigger DDL sobre o evento DELETE de uma tabela qualquer utilizando por exemplo a instrução: GRANT CONTROL SERVER TO BadUser; Quando o usuário João da Silva executar o procedimento que dispara a trigger o Grant será delegado ao usuário mal intencionado e os direitos aplicados a ele, enquanto ele mesmo não teria acesso para delegar tal direito, deste modo possibilitando que o desenvolvedor mal intencionado tome conta do servidor SQL, podendo fazer o que bem entender com os dados.

Security: http://msdn.microsoft.com/pt-br/library/ms191134.aspx

Visual Studio

Para efetuar as conexões com os diferentes bancos de dados você precisa primeiro configurar seu projeto com os assemblers ADO.NET  necessários e depois você pode criar um design com 3 componentes RadioButton, 2 componentes Labels, 2 componentes TextBoxes e um componente Button e um componente DataGridView use a figura abaixo para referencia:

Triggers - Design Time

Triggers – Design Time

IBM Data Studio

O IBM Data Studio possui uma funcionalidade especifica para criar triggers (Wizard), assim como possui para Stored Procedures e Function no qual necessitam de executar um Deploy antes de ser executada. Portanto você não poderá criar a Trigger utilizando a configuração Default do editor SQL comum, para isto você precisa mudar a configuração do terminador de instrução de ponto e virgula (;) para arroba(@), basta clicar com o botão direito do mouse e escolher a opção: Configurar Terminador de Instrução. Utilize a figura abaixo para referencia:

IBM Data Studio - Configuração

IBM Data Studio – Configuração

Exemplo:

Neste exemplo criamos uma funcionalidade similar do nosso exemplo anterior (Cursor), utilizando a mesma modelagem de dados, porem para executar este procedimento as tabelas DESCONTO e SALARIO devem estar vazias, o usuário entrará com o código do funcionário e a porcentagem do desconto e a trigger sobre a tabela DESCONTO se encarregara de criar o lançamento na tabela de SALARIO.

SQL

Oracle

create table Funcionarios(
  ID_Funcionario  NUMBER(5),
  Nome            VARCHAR2(30),
  Sobrenome       VARCHAR2(70),
  Cargo           VARCHAR2(30),
  Salario         NUMBER(9,2));

-- Cria Funcionarios
Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);
Insert into FUNCIONARIOS values (3,'Wozniak','Gates','Desenvolvedor', 4389.21);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO NUMBER,
  PORCENTAGEM NUMBER(9,2));

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO NUMBER,
  DATA_LANC  DATE,
  VDESCONTO NUMBER(9,2));

-- Deleta dados antigos
-- Caso utlizou exemplos anteriores
delete from desconto;
delete from salario;

-- Cria trigger na tabela Desconto
create or replace TRIGGER DESCONTO_INSERT
   BEFORE INSERT ON DESCONTO
   FOR EACH ROW

   -- Declara variáveis
   DECLARE pID NUMBER;
           pSalario NUMBER(9,2);
           pPorcentagem NUMBER(9,2);
   BEGIN   

    -- Alimenta variáveis com os valores a serem inseridos
    pID := :new.ID_FUNCIONARIO;
    pPorcentagem := :new.PORCENTAGEM;

    -- Seleciona Salario do funcionario corrente
    Select SALARIO INTO pSalario FROM FUNCIONARIOS
    WHERE ID_FUNCIONARIO = pID;

    -- insere na tabela de lançamentos de salario
    Insert into SALARIO
     values (
             pID,
             SYSDATE,
             (pSalario * pPorcentagem)/100);

   END DESCONTO_INSERT;

DB2

create table Funcionarios (
    ID_Funcionario  INTEGER,
    Nome            VARCHAR(30),
    Sobrenome       VARCHAR(70),
    Cargo           VARCHAR(30),
    Salario         NUMERIC(9,2))@

Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56)@
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71)@
Insert into FUNCIONARIOS values (3,'Wozniak','Gates','Desenvolvedor', 4389.21)@

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INTEGER,
  PORCENTAGEM DECIMAL(9,2))@

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO INTEGER,
  DATA_LANC  DATE,
  VDESCONTO DECIMAL(9,2))@

-- Deleta dados antigos
-- Caso utlizou exemplos anteriores
delete from desconto@
delete from salario@

-- Cria trigger na tabela Desconto
create TRIGGER DESCONTO_INSERT
   BEFORE INSERT ON DESCONTO
   REFERENCING NEW AS N
   FOR EACH ROW

 P1:  BEGIN

   -- Declara variáveis
   DECLARE pID NUMBER;
   DECLARE pSalario DECIMAL(9,2);
   DECLARE pPorcentagem DECIMAL(9,2);

    -- Alimenta variáveis com os valores a serem inseridos
    SET pID = N.ID_FUNCIONARIO;
    SET pPorcentagem = N.PORCENTAGEM;

    -- Seleciona Salario do funcionario corrente
    Select SALARIO INTO pSalario FROM FUNCIONARIOS
    WHERE ID_FUNCIONARIO = pID;

    -- insere na tabela de lançamentos de salario
    Insert into SALARIO
     values (
             pID,
             SYSDATE,
             (pSalario * pPorcentagem)/100);

   END P1

MSSQL

create table Funcionarios (
   ID_Funcionario  Int,
   Nome            VARCHAR(30),
   Sobrenome       VARCHAR(70),
   Cargo           VARCHAR(30),
   Salario         Decimal(9,2));

Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);
Insert into FUNCIONARIOS values (3,'Wozniak','Gates','Desenvolvedor', 4389.21);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INT,
  PORCENTAGEM DECIMAL(9,2));

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO INT,
  DATA_LANC  DATE,
  VDESCONTO DECIMAL(9,2));

-- Deleta dados antigos
-- Caso utlizou exemplos anteriores
delete from desconto;
delete from salario;

-- Cria trigger na tabela Desconto
create TRIGGER DESCONTO_INSERT ON
  DESCONTO AFTER INSERT AS      

   BEGIN
   -- Declara variáveis
   DECLARE @pID Int,
           @pSalario DECIMAL(9,2),
           @pPorcentagem DECIMAL(9,2); 

    -- Alimenta variáveis com os valores a serem inseridos
	Select @pID = ID_FUNCIONARIO,
	       @pPorcentagem = PORCENTAGEM
    from inserted;

    -- Seleciona Salario do funcionario corrente
    Select  @pSalario = SALARIO FROM FUNCIONARIOS
    WHERE ID_FUNCIONARIO = @pID;

    -- insere na tabela de lançamentos de salario
    Insert into SALARIO
     values (
             @pID,
             GETDATE(),
             (@pSalario * @pPorcentagem)/100);

   END;

C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Data.SqlClient;
using Oracle.DataAccess.Client;
using IBM.Data.DB2; 

namespace Acesso
{
    public partial class Dados : Form
    {
        private static OracleConnection connORA; // ODAC 12c
        private static DB2Connection connDB2;   // IBM Data Server Provider
        private static SqlConnection connMSSQL; // ADO .NET

        DataTable dataTable;

        string sql;
        static string bancodedados;

        public Dados()
        {
            InitializeComponent();
        }

        // Cria métodos de conexão
        // Você pode optar por um unico método se usar apenas ADO.NET
        // Neste caso usamos os drivers nativos de conexão de cada banco de dados.
        // Todos os drivers são baseados em ADO .NET
        public void conexaoODAC(string Username, string Password, string Datasource)
        {
            try
            {
                // String de Conexao
                string connectionString =

                    // Usuario
                    "User Id=" + Username +

                    // Senha
                    ";Password=" + Password +

                    // TNSnames
                    ";Data Source=" + Datasource;

                //Conecta ao datasource usando a conexão Oracle
                 connORA = new OracleConnection(connectionString);

                //Abre a conexão com o banco de dados
                connORA.Open();

            }
            // Retorna erro
            catch (Exception ex)
            {
                // Mostra menssagem de erro
                MessageBox.Show(ex.ToString());

            }
        }

        void conexaoDB2(string Server, string Database,
                                    string Username, string Password, string Timeout)
        {
            try
            {
                // String de Conexao
                string connectionString =

                    // Servidor
                    "Server=" + Server +

                    // Banco de dados
                    ";Database=" + Database +

                    // Usuario
                    ";UID=" + Username +

                    // Senha
                    ";PWD=" + Password +

                    // TNSnames
                    ";Connect Timeout=" + Timeout;

                //Conecta ao datasource usando a conexão DB2
                connDB2 = new DB2Connection(connectionString);

                //Abre a conexão com o banco de dados
                connDB2.Open();                

            }
            // Retorna erro
            catch (Exception ex)
            {
                // Mostra menssagem de erro
                MessageBox.Show(ex.ToString());

            }
        }

         public void conexaoMSSQL(string Server, string Database,
                                     string Username, string Password, string Timeout)
         {
             try
             {
                 // String de Conexao
                 string connectionString =

                     // Servidor
                     "Data Source=" + Server +

                     // Banco de dados
                     ";Initial Catalog=" + Database +

                     // Usuario
                     ";User ID =" + Username +

                     // Senha
                     ";Password=" + Password +

                     // TNSnames
                     ";Connect Timeout=" + Timeout;

                 //Conecta ao datasource usando a conexão Padrão
                 connMSSQL = new SqlConnection(connectionString);

                 //Abre a conexão com o banco de dados
                 connMSSQL.Open();

             }
             // Retorna erro
             catch (Exception ex)
             {
                 // Mostra menssagem de erro
                 MessageBox.Show(ex.ToString());

             }
         }

        // Retorna um set de dados
         public  DataTable retornaTabela(string sql, string sqlTrigger)
         {
             // Declara comandos para Stored Procedure
             OracleCommand cmdORA;
             DB2Command cmdDB2;
             SqlCommand cmdSQL;

             // Cria instância da classe
             Dados acesso = new Dados();

             // Define banco de dados

             if (bancodedados == "oracle")
             {
                 // Efetua Login no banco de dados
                 acesso.conexaoODAC("daberto", "p@55w0rd", "XE");

                 // Define a instrução SQL e a conexão
                 cmdORA = new OracleCommand(sqlTrigger, connORA);

                 // Executa query
                 cmdORA.ExecuteNonQuery();

                 // Cria comandos para retornar dados para exibir a grade de dados
                 OracleCommand oracmd = new OracleCommand(sql, connORA);
                 OracleDataReader orareader = oracmd.ExecuteReader();
                 dataTable = new DataTable();
                 dataTable.Load(orareader);
             }

             if (bancodedados == "db2")
             {
                 acesso.conexaoDB2("localhost", "DEVA", "db2admin", "p@55w0rd", "40");

                 cmdDB2 = new DB2Command(sqlTrigger, connDB2);

                 cmdDB2.ExecuteNonQuery();

                 DB2Command db2cmd = new DB2Command(sql);
                 db2cmd.Connection = connDB2;
                 DB2DataReader db2reader = db2cmd.ExecuteReader();
                 dataTable = new DataTable();
                 dataTable.Load(db2reader);                

             }

             if (bancodedados == "mssql")
             {
                 acesso.conexaoMSSQL("localhost", "DevAberto", "devaberto", "p@55w0rd", "");

                 cmdSQL = new SqlCommand(sqlTrigger, connMSSQL);

                 cmdSQL.ExecuteNonQuery();

                 SqlCommand mssqlcmd = new SqlCommand(sql);
                 mssqlcmd.Connection = connMSSQL;
                 SqlDataReader mssqlreader = mssqlcmd.ExecuteReader();
                 dataTable = new DataTable();
                 dataTable.Load(mssqlreader);

             }

             return  dataTable;
         }

        // configura programa
        private void Form1_Shown(object sender, EventArgs e)
        {
            radioButton1.Checked = true;
            bancodedados = "oracle";
        }

        // Conecta dados
        private void button1_Click(object sender, EventArgs e)
        {
            // Cria instância da classe
            Dados dados = new Dados();

            // Insere Porcentagem de desconto e executa trigger
            string sqltrigger = "insert into DESCONTO VALUES (" + textBox1.Text +
                              ", " + textBox2.Text + ")";

            // Exibe relatorio de lançamentos
            string sql = "Select A.ID_FUNCIONARIO, " + "A.NOME, " + " A.CARGO, "
                       + " A.SALARIO, " + "B.PORCENTAGEM, " + "C.VDESCONTO, "
                       + "C.DATA_LANC,  " + "A.SALARIO - C.VDESCONTO AS SLIQUIDO "
                       + "from FUNCIONARIOS A, DESCONTO B, SALARIO C " + "Where "
                       + "A.ID_FUNCIONARIO = B.ID_FUNCIONARIO  AND "
                       + "A.ID_FUNCIONARIO = C.ID_FUNCIONARIO";

            // Alimenta grid de dados
            dataGridView1.DataSource = dados.retornaTabela(sql, sqltrigger);

        }

        // Seleciona banco de dados Oracle
        private void radioButton1_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButton1.Checked)
            {
                bancodedados = "oracle";
            }

        }

        // Seleciona banco de dados IBM DB2
        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButton2.Checked)
            {
                bancodedados = "db2";
            }
        }

        // Seleciona banco de dados MSSQL Server
        private void radioButton3_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButton3.Checked)
            {
                bancodedados = "mssql";
            }
        }
    }
}

Uma Trigger ou gatilho é um tipo especial de procedimento armazenado (Stored Procedure) que executa automaticamente quando um evento ocorre no servidor de banco de dados. Gatilhos DML executam quando um usuário tenta modificar dados através de uma linguagem de manipulação de dados (DML). Eventos DML são INSERT, UPDATE, ou DELETE em uma tabela ou exibição. Esses gatilhos disparam quando qualquer evento válido é acionado, independentemente de haver ou não linhas da tabela afetadas.

As Triggers possuem muitas diferenças de sintaxe e funcionalidades de um banco de dados para outro, por exemplo Trigger que dispara o evento INSTEAD OF INSERT (ao invés de inserir) no banco de dados Oracle só pode ser declarada sobre uma VIEW enquanto em MSSQL Server pode ser declarada em uma tabela comum, o evento BEFORE INSERT (antes de inserir) existe nos bancos de dados Oracle e IBM DB2, mas não existe no MSSQL. Por este motivo é recomendado que você procure os links oficiais para saber mais detalhes sobre as Triggers.

Triggers - Oracle - DB2 - MSSQL

Triggers – Oracle – DB2 – MSSQL

 

Algo extremamente útil que você deve saber sobre Triggers

As Triggers foram regulamentadas na revisão da língua SQL em 1999 e passou a ser padrão em banco de dados relacionais, no entanto alguns bancos de dados vem atualizando estes recursos regularmente, por exemplo o Oracle utiliza Triggers que disparam por esquema (Schema-level triggers) desde a sua versão 9i, enquanto o MSSQL suporta trigger do tipo DDL, ou logon trigger apenas desde a versão 2008.

Muitos sistemas de grande porte como SAP e vários outros não utilizam triggers, principalmente sistemas que no qual rodam em diversos bancos de dados, estas são consideradas verdadeiras armadilhas por muitos DBAs, podem ser facilmente esquecidas na hora de alterações e se tornarem invalidas (Oracle), gerando assim muitos erros caso não haja uma boa politica de desenvolvimento e qualidade (testes unitários e integrados) antes de colocar as rotinas do sistema em produção. Mesmo as IDEs de estudios SQL já mudaram varias vezes a localização do node de triggers ao longo de suas versões para tentar facilitar a manutenção das mesmas, aqui veremos como exemplo a IDE do IBM Data Studio que possui um wizard especifico para triggers.

As Triggers também devem ser desenvolvidas com cuidado sempre seguindo as melhores praticas, pois o desenvolvimento SQL é muito abrangentes e cheio de recursos, então é fácil extrapolar e criar triggers contendo cursores, stored procedures, rollbacks, acessos repetitivos, outras triggers, lembre-se da lei de Murphy, tudo que não pode ser escrito em uma trigger, será e isto reduz sensivelmente a performance de um sistema, sem contar com a complexidade do desenvolvimento, transformado seu desenvolvimento SQL em verdadeiros planos da ACME, lembre-se do coite que tentava incessantemente capturar o papa-léguas.

Cuidado com as Triggers

Cuidado com as Triggers

Nunca use Triggers para criar campos auto incremento para os códigos (ID), os bancos de dados possuem recursos específicos para este trabalho, o uso de triggers somente criará acessos e UPDATES desnecessários no banco de dados, além de reduzir a performance, imagine importar 10.000 linhas utilizando um Insert…Select, à partir de uma outra tabela ou arquivos externos, você efetuara um Select e um Update para cada registro se utilizar triggers, enquanto os bancos de dados contam com seus campos auto incremento que já nos permitem utilizar dados em massa e inserir as 10.000 linhas em um único acesso.

As Triggers também são um alto risco a segurança, é possível escalar privilégios e se tornar proprietário do banco de dados e do servidor SQL caso você insira um código mal intencionado em uma Trigger, exemplo: suponha que o usuário Jõao da Silva tenha diretos de Administrador do banco de dados,  se um desenvolvedor mal intencionado criar uma trigger DDL sobre o evento DELETE de uma tabela qualquer utilizando por exemplo a instrução: GRANT CONTROL SERVER TO BadUser; Quando o usuário João da Silva executar o procedimento que dispara a trigger o Grant será delegado ao usuário mal intencionado e os direitos aplicados a ele, enquanto ele mesmo não teria acesso para delegar tal direito, deste modo possibilitando que o desenvolvedor mal intencionado tome conta do servidor SQL, podendo fazer o que bem entender com os dados.

Security: http://msdn.microsoft.com/pt-br/library/ms191134.aspx

IBM Data Studio

O IBM Data Studio possui uma funcionalidade especifica para criar triggers (Wizard), assim como possui para Stored Procedures e Function no qual necessitam de executar um Deploy antes de ser executada. Portanto você não poderá criar a Trigger utilizando a configuração Default do editor SQL comum, para isto você precisa mudar a configuração do terminador de instrução de ponto e virgula (;) para arroba(@), basta clicar com o botão direito do mouse e escolher a opção: Configurar Terminador de Instrução. Utilize a figura abaixo para referencia:

IBM Data Studio - Configuração

IBM Data Studio – Configuração

Exemplo:

Neste exemplo criamos uma funcionalidade similar do nosso exemplo anterior (Cursor), utilizando a mesma modelagem de dados, porem para executar este procedimento as tabelas DESCONTO e SALARIO devem estar vazias, o usuário entrará com o código do funcionário e a porcentagem do desconto e a trigger sobre a tabela DESCONTO se encarregara de criar o lançamento na tabela de SALARIO.

SQL

Oracle

create table Funcionarios(
  ID_Funcionario  NUMBER(5),
  Nome            VARCHAR2(30),
  Sobrenome       VARCHAR2(70),
  Cargo           VARCHAR2(30),
  Salario         NUMBER(9,2));

-- Cria Funcionarios
Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);
Insert into FUNCIONARIOS values (3,'Wozniak','Gates','Desenvolvedor', 4389.21);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO NUMBER,
  PORCENTAGEM NUMBER(9,2));

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO NUMBER,
  DATA_LANC  DATE,
  VDESCONTO NUMBER(9,2));

-- Deleta dados antigos
-- Caso utlizou exemplos anteriores
delete from desconto;
delete from salario;

-- Cria trigger na tabela Desconto
create or replace TRIGGER DESCONTO_INSERT
   BEFORE INSERT ON DESCONTO
   FOR EACH ROW

   -- Declara variáveis
   DECLARE pID NUMBER;
           pSalario NUMBER(9,2);
           pPorcentagem NUMBER(9,2);
   BEGIN   

    -- Alimenta variáveis com os valores a serem inseridos
    pID := :new.ID_FUNCIONARIO;
    pPorcentagem := :new.PORCENTAGEM;

    -- Seleciona Salario do funcionario corrente
    Select SALARIO INTO pSalario FROM FUNCIONARIOS
    WHERE ID_FUNCIONARIO = pID;

    -- insere na tabela de lançamentos de salario
    Insert into SALARIO
     values (
             pID,
             SYSDATE,
             (pSalario * pPorcentagem)/100);

   END DESCONTO_INSERT;

DB2

create table Funcionarios (
    ID_Funcionario  INTEGER,
    Nome            VARCHAR(30),
    Sobrenome       VARCHAR(70),
    Cargo           VARCHAR(30),
    Salario         NUMERIC(9,2))@

Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56)@
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71)@
Insert into FUNCIONARIOS values (3,'Wozniak','Gates','Desenvolvedor', 4389.21)@

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INTEGER,
  PORCENTAGEM DECIMAL(9,2))@

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO INTEGER,
  DATA_LANC  DATE,
  VDESCONTO DECIMAL(9,2))@

-- Deleta dados antigos
-- Caso utlizou exemplos anteriores
delete from desconto@
delete from salario@

-- Cria trigger na tabela Desconto
create TRIGGER DESCONTO_INSERT
   BEFORE INSERT ON DESCONTO
   REFERENCING NEW AS N
   FOR EACH ROW

 P1:  BEGIN

   -- Declara variáveis
   DECLARE pID NUMBER;
   DECLARE pSalario DECIMAL(9,2);
   DECLARE pPorcentagem DECIMAL(9,2);

    -- Alimenta variáveis com os valores a serem inseridos
    SET pID = N.ID_FUNCIONARIO;
    SET pPorcentagem = N.PORCENTAGEM;

    -- Seleciona Salario do funcionario corrente
    Select SALARIO INTO pSalario FROM FUNCIONARIOS
    WHERE ID_FUNCIONARIO = pID;

    -- insere na tabela de lançamentos de salario
    Insert into SALARIO
     values (
             pID,
             SYSDATE,
             (pSalario * pPorcentagem)/100);

   END P1

MSSQL

create table Funcionarios (
   ID_Funcionario  Int,
   Nome            VARCHAR(30),
   Sobrenome       VARCHAR(70),
   Cargo           VARCHAR(30),
   Salario         Decimal(9,2));

Insert into FUNCIONARIOS values (1,'Steve','Gates','Programador',2550.56);
Insert into FUNCIONARIOS values (2,'Bill','Jobs','Diretor',5143.71);
Insert into FUNCIONARIOS values (3,'Wozniak','Gates','Desenvolvedor', 4389.21);

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INT,
  PORCENTAGEM DECIMAL(9,2));

-- Cria tabela de lançamentos de descontos
Create table SALARIO (
  ID_FUNCIONARIO INT,
  DATA_LANC  DATE,
  VDESCONTO DECIMAL(9,2));

-- Deleta dados antigos
-- Caso utlizou exemplos anteriores
delete from desconto;
delete from salario;

-- Cria trigger na tabela Desconto
create TRIGGER DESCONTO_INSERT ON
  DESCONTO AFTER INSERT AS      

   BEGIN
   -- Declara variáveis
   DECLARE @pID Int,
           @pSalario DECIMAL(9,2),
           @pPorcentagem DECIMAL(9,2); 

    -- Alimenta variáveis com os valores a serem inseridos
	Select @pID = ID_FUNCIONARIO,
	       @pPorcentagem = PORCENTAGEM
    from inserted;

    -- Seleciona Salario do funcionario corrente
    Select  @pSalario = SALARIO FROM FUNCIONARIOS
    WHERE ID_FUNCIONARIO = @pID;

    -- insere na tabela de lançamentos de salario
    Insert into SALARIO
     values (
             @pID,
             GETDATE(),
             (@pSalario * @pPorcentagem)/100);

   END;

Java

import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;

public class Cursor implements ActionListener, ItemListener {
	// Cria componentes
	private JTable tabela;
	private JRadioButton banco1;
	private JRadioButton banco2;
	private JRadioButton banco3;
	private JButton botao;
	private JLabel lid_funcionario;
	private JLabel lporcentagem;
	private JTextField tid_funcionario;
	private JTextField tporcentagem;

	// Declara objetos de conexão
	private static Connection conn;
	private static Statement query;
	private static String bancodedados;

	public void conectar(String login, String senha) {

		// Verifica strings de conexão

		// ORACLE
		if (bancodedados == "oracle") {
			try {
				// Define Driver de conexão JDBC thin
				Class.forName("oracle.jdbc.driver.OracleDriver");
				conn = DriverManager.getConnection(
						"jdbc:oracle:thin:@localhost:1521:xe", login, senha);

				// Executa pedido SQL
				query = conn.createStatement();

			}

			catch (ClassNotFoundException ex) {
				ex.printStackTrace();
			}

			catch (SQLException ex) {
				ex.printStackTrace();
			}
		}

		// DB2
		if (bancodedados == "db2") {
			try {
				// Define Driver de conexão JDBC
				Class.forName("com.ibm.db2.jcc.DB2Driver");
				conn = DriverManager.getConnection(
						"jdbc:derby:net://localhost:50000/deva", login, senha);

				// Executa pedido SQL
				query = conn.createStatement();
				// JOptionPane.showMessageDialog(menssagem,
				// "Conexão Efetuada com sucesso!");
			}

			catch (ClassNotFoundException ex) {
				ex.printStackTrace();
			}

			catch (SQLException ex) {
				// JOptionPane.showMessageDialog(menssagem, "Erro na conexão!");
				ex.printStackTrace();
			}

		}

		// MICROSOFT SQL SERVER
		if (bancodedados == "mssql") {
			try {
				// Define Driver de conexão JDBC
				String URL = "jdbc:sqlserver://localhost\\SQLEXPRESS:1433;databaseName=devaberto"
						+ ";user=" + login + ";password=" + senha;

				Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
				conn = DriverManager.getConnection(URL);

				// Executa pedido SQL
				query = conn.createStatement();

			}

			catch (ClassNotFoundException ex) {
				ex.printStackTrace();
			}

			catch (SQLException ex) {
				ex.printStackTrace();
			}

		}

	}

	public void executaSQL(String sql)   {
		// Cria nova instrução SQL
		Statement trigger;
		;
		try {
			trigger = conn.createStatement();
			trigger.execute(sql);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public ResultSet retornaTabela() throws SQLException {
		// Cria nova instrução SQL
		Statement query;
		query = conn.createStatement();
		String sql;

		// Verfica banco de dados e passa script SQL
		sql = "Select A.ID_FUNCIONARIO, " + "A.NOME, " + " A.CARGO, "
				+ " A.SALARIO, " + "B.PORCENTAGEM, " + "C.VDESCONTO, "
				+ "C.DATA_LANC,  " + "A.SALARIO - C.VDESCONTO AS SLIQUIDO "
				+ "from FUNCIONARIOS A, DESCONTO B, SALARIO C " + "Where "
				+ "A.ID_FUNCIONARIO = B.ID_FUNCIONARIO  AND "
				+ "A.ID_FUNCIONARIO = C.ID_FUNCIONARIO";

		// Executa Script
		ResultSet dados = query.executeQuery(sql);

		// Retorna set de dados
		return dados;
	}

	// Modelo
	public static DefaultTableModel criaTableModel(ResultSet rs)
			throws SQLException {

		// Cria um modelo de tabela
		ResultSetMetaData metaData = rs.getMetaData();

		// Retorna as colunas
		Vector<String> colunas = new Vector<String>();

		int columnCount = metaData.getColumnCount();

		for (int column = 1; column <= columnCount; column++) {
			colunas.add(metaData.getColumnName(column));
		}

		// Retorna dados
		Vector<Vector<Object>> dados = new Vector<Vector<Object>>();

		while (rs.next()) {
			Vector<Object> vector = new Vector<Object>();

			for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) {
				vector.add(rs.getObject(columnIndex));
			}
			dados.add(vector);
		}

		return new DefaultTableModel(dados, colunas);

	}

	public void itemStateChanged(ItemEvent arg0) {

		// Verifica item banco de dados selecionado
		Object fonte = arg0.getItemSelectable();
		int estado = arg0.getStateChange();

		if (estado == arg0.SELECTED) {

			if (fonte == banco1) {
				bancodedados = "oracle";
			}

			if (fonte == banco2) {
				bancodedados = "db2";
			}

			if (fonte == banco3) {
				bancodedados = "mssql";
			}

		}

	}

	public void actionPerformed(ActionEvent arg0) {
		// Efetua login no banco de dados
		Cursor acesso = new Cursor();

		if (bancodedados == "oracle") {
			acesso.conectar("daberto", "p@55w0rd");
		}

		if (bancodedados == "db2") {
			acesso.conectar("db2admin", "p@55w0rd");
		}

		if (bancodedados == "mssql") {
			acesso.conectar("devaberto", "p@55w0rd");
		}

		try {
			// Executa Trigger (Tabela Desconto)

			acesso.executaSQL("insert into DESCONTO VALUES ("+ tid_funcionario.getText() +
					          ", " + tporcentagem.getText() + ")");

			// Executa Intrução SQL
			tabela.setModel(criaTableModel(acesso.retornaTabela()));
		} catch (SQLException e) {
			e.printStackTrace();
		}

	}

	public Container criaPainel() throws SQLException {
		// Cria painel principal
		JPanel painel = new JPanel();

		// Seleciona layout
		painel.setLayout(new BoxLayout(painel, BoxLayout.PAGE_AXIS));
		painel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

		// Cria painel de escolha de conexão
		JPanel pescolha = new JPanel();

		pescolha.setLayout(new BoxLayout(pescolha, BoxLayout.LINE_AXIS));
		pescolha.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

		ButtonGroup grupo = new ButtonGroup();

		// Cria componentes de radio
		banco1 = new JRadioButton("Oracle");
		banco2 = new JRadioButton("IBM DB2");
		banco3 = new JRadioButton("Microsoft SQL");

		// Agrupa botões de radio
		grupo.add(banco1);
		grupo.add(banco2);
		grupo.add(banco3);

		// Cria ouvinte dos botões
		banco1.addItemListener(this);
		banco2.addItemListener(this);
		banco3.addItemListener(this);

		// Seleciona primeira conexão
		banco1.setSelected(true);

		// Adiciona botões ao painel
		pescolha.add(banco1);
		pescolha.add(banco2);
		pescolha.add(banco3);

		// Efetua primeira conexão ao banco (ORACLE)
		Cursor acesso = new Cursor();

		acesso.conectar("daberto", "myoracle123");

		// Cria modelo de tabela
		tabela = new JTable(criaTableModel(acesso.retornaTabela()));

		// Adiciona um painel de rolagem
		JScrollPane rolar = new JScrollPane(tabela);

		// Cria painel do botão
		JPanel pbotao = new JPanel(new GridLayout(0, 5, 10, 10));		

		// Cria botão
		lid_funcionario = new JLabel("Código Func:");
		lporcentagem = new JLabel("Porcentagem:");

		tid_funcionario = new JTextField();
		tporcentagem = new JTextField();

		botao = new JButton("Inserir");
		botao.addActionListener(this);

		// Define foco do cursor
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                tid_funcionario.requestFocus();
            }
        });

		// Adiciona botão ao painel
		pbotao.add(lid_funcionario);
		pbotao.add(tid_funcionario);
		pbotao.add(lporcentagem);
		pbotao.add(tporcentagem);
		pbotao.add(botao);

		// componentes ao painel principal
		painel.add(pescolha);
		painel.add(rolar);
		painel.add(Box.createVerticalStrut(10));
		painel.add(pbotao);

		return painel;
	}

	public static void criaGUI() {
		// Cria formulario
		JFrame formulario = new JFrame("Desenvolvimento Aberto - Triggers");
		formulario.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		// cria painel de conteudo
		Cursor acesso = new Cursor();

		try {
			formulario.setContentPane(acesso.criaPainel());
		}

		catch (SQLException e) {
			e.printStackTrace();
		}

		// Exibe o formulario
		formulario.setSize(700, 300);
		formulario.setVisible(true);
	}

	public static void main(String[] args) {
		javax.swing.SwingUtilities.invokeLater(new Runnable() {

			@Override
			public void run() {

				// Cria e mostra a GUI
				criaGUI();

			}
		});
	}
}

Você pode utilizar as funções NMIN e NMAX para retornar os valores mínimos e máximos entre pelo menos dois parâmetros. Estas funções fazem o mesmo trabalho da clausula IF efetuando comparações utilizando os sinais de maior (>) ou menor (<), porem possuem uma sintaxe muito menos complexa se utilizados muitos parâmetros.

Fora de uma expressão aritmética, um tipo de cálculo é determinado a partir de todos os argumentos, e é utilizado para realizar a comparação. O tipo de cálculo é determinado apenas como uma expressão aritmética e também determina o tipo do valor de retorno de dados.

Em uma expressão aritmética, os argumentos da função contribuem para o tipo de cálculo de toda a expressão e a função é calculada usando o tipo do cálculo. Se um argumento em si é uma expressão aritmética, os operandos contribuem para todo o tipo de cálculo e o argumento também é calculado usando esse mesmo tipo.

 

Funções - Extremum

Funções – Extremum

Exemplo:

Neste exemplo criamos uma tela de seleção com três parâmetros e as funções Extremum verificam e exibem uma mensagem retornando o maior e o menor parâmetro dentro das possibilidades alimentadas pelo usuário.

Abap

*&---------------------------------------------------------------------*
*& Report  ZMAXMIN
*&
*&---------------------------------------------------------------------*
*& Desenvolvimento Aberto
*& Numerical Extremum Functions
*&---------------------------------------------------------------------*

REPORT  ZMAXMIN.

* Cria parametros de seleção
SELECTION-SCREEN COMMENT /1(10) text-par.
PARAMETERS: valor1 TYPE i DEFAULT 0,
            valor2 TYPE i DEFAULT 0,
            valor3 TYPE i DEFAULT 0.

* Declara variáveis
DATA:   minimo    TYPE decfloat34,
        maximo    TYPE decfloat34,
        val1      TYPE decfloat34,
        val2      TYPE decfloat34,
        val3      TYPE decfloat34,
        txt       TYPE string.

* Inicio da seleção
START-OF-SELECTION.

* Verifica os valores minimos e máximos
minimo =  nmin( val1 = valor1 val2 = valor2 val3 = valor3 ).
maximo =  nmax( val1 = valor1 val2 = valor2 val3 = valor3 ).

* Cria texto da menssagem
 txt = |{ txt } o valor minimo é: { minimo } e o valor máximo é: { maximo } |.

* Exibe menssagem de informação
 MESSAGE txt TYPE 'I'.

* Exibe menssagem de erro (valida campos)
AT SELECTION-SCREEN.
  IF valor1 = 0 or valor2 = 0 or valor3 = 0.
    MESSAGE 'Você deve entrar com um valor diferente de zero' TYPE 'E'.
  ENDIF.