desenvolvendo triggers em sql

7
Desenvolvendo Triggers em SQL Server, Oracle, Firebird e Postgres http://www.devmedia.com.br/articles/viewcomp.asp?comp=5625&hl=*oracle* empresas que desenvolvem aplicativos para diversos bancos de dados passam por uma dúvida sobre como tratar as regras de negócio: elas ficam na aplicação ou devem ser escritas no banco de dados. quando é optado por deixar as regras na aplicação, a vantagem está na portabilidade, porque não será necessário reescrever estas regras em cada linguagem que é disponibilizada pelos fornecedores de sgbd. por outro lado quem opta por colocar tudo no banco de dados garante uma maior integridade das informações, e normalmente tem algum ganho de desempenho por deixar procedimentos pesados no lado do servidor do banco de dados. neste artigo será abordada somente uma pequena parte deste assunto. o objetivo é comentar algumas das diferenças existentes na criação de triggers nos seguintes bancos de dados: sql server, oracle, firebird e postgres. 1. modelo empregado pelo artigo para explicarmos as diferenças entre os bancos de dados escolhidos para este artigo, criaremos a mesma trigger em todos eles. o objetivo desta trigger será impedir que em uma nota fiscal sejam incluídos mais do que trinta itens, dando uma mensagem sempre que isto acontecer. foram definidas duas tabelas simplificadas: uma de nota fiscal (tabela 1) e outra com os itens da nota fiscal (tabela 2) campo tipo #idnotafiscal inteiro idcliente inteiro datavenda data tabela 1. definição da tabela de notas fiscais campo tipo #idnotafiscal inteiro #iditem inteiro idproduto inteiro preço unitário numérico quantidade numérico tabela 2. definição da tabela de itens da nota fiscal 2. listagens das triggers a seguir estão relacionados os códigos da trigger nos quatro bancos de dados

Upload: diflango

Post on 26-Jun-2015

159 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Desenvolvendo Triggers Em SQL

Desenvolvendo Triggers em SQL Server, Oracle,

Firebird e Postgreshttp://www.devmedia.com.br/articles/viewcomp.asp?comp=5625&hl=*oracle*

empresas que desenvolvem aplicativos para diversos bancos de dados passam por uma dúvida sobre como tratar as regras de negócio: elas ficam na aplicação ou devem ser escritas no banco de dados.quando é optado por deixar as regras na aplicação, a vantagem está na portabilidade, porque não será necessário reescrever estas regras em cada linguagem que é disponibilizada pelos fornecedores de sgbd. por outro lado quem opta por colocar tudo no banco de dados garante uma maior integridade das informações, e normalmente tem algum ganho de desempenho por deixar procedimentos pesados no lado do servidor do banco de dados.neste artigo será abordada somente uma pequena parte deste assunto. o objetivo é comentar algumas das diferenças existentes na criação de triggers nos seguintes bancos de dados: sql server, oracle, firebird e postgres.

1.    modelo empregado pelo artigo

para explicarmos as diferenças entre os bancos de dados escolhidos para este artigo, criaremos a mesma trigger em todos eles. o objetivo desta trigger será impedir que em uma nota fiscal sejam incluídos mais do que trinta itens, dando uma mensagem sempre que isto acontecer.foram definidas duas tabelas simplificadas: uma de nota fiscal (tabela 1) e outra com os itens da nota fiscal (tabela 2)

campo tipo#idnotafiscal inteiroidcliente inteirodatavenda data

tabela 1. definição da tabela de notas fiscais

campo tipo#idnotafiscal inteiro#iditem inteiroidproduto inteiropreço unitário numéricoquantidade numérico

tabela 2. definição da tabela de itens da nota fiscal

2.    listagens das triggers

a seguir estão relacionados os códigos da trigger nos quatro bancos de dados

listagem 2. trigger para o sql server

-- exclui a trigger caso ela já exista.

if object_id ('tr_in_item','tr') is not null drop trigger tr_in_itemgo

create trigger tr_in_item on item after insert

Page 2: Desenvolvendo Triggers Em SQL

asdeclare @ltotalitens int, @lnota intbegin -- seleciona o código da nota que está sendo incluída. select @lnota = idnota from inserted; -- totaliza a quantidade de itens já cadastrados na nota. select @ltotalitens = count(*) from item where idnota = @lnota; -- verifica se existem mais do que 30 itens na nota. if @ltotalitens > 30 begin raiserror('a nota %d já está cheia. inclusão cancelada.',16,1,@lnota); rollback; endendgo

listagem 3. trigger para o firebird

create exception nota_cheia 'a nota já está cheia. inclusão cancelada.';

create trigger tr_in_item for item after insertasdeclare ltotalitens integer;declare lnota integer;begin -- seleciona o código da nota que está sendo incluída. lnota = new.idnota; -- totaliza a quantidade de itens já cadastrados na nota. select count(*) from item where idnota = :lnota into :ltotalitens; -- verifica se existem mais do que 30 itens na nota. if (ltotalitens > 30) then begin exception nota_cheia; endend

listagem 4. trigger para o postgre em pl/pgsql

create or replace function tr_in_item() returns trigger as $tr_in_item$declare ltotalitens int;declare lnota int;begin -- seleciona o código da nota que está sendo incluída. lnota := new.idnota; -- totaliza a quantidade de itens já cadastrados na nota. select into ltotalitens count(*) from item where idnota = lnota; -- verifica se existem mais do que 30 itens na nota. if (ltotalitens > 30) then

Page 3: Desenvolvendo Triggers Em SQL

raise exception 'a nota % já está cheia. inclusão cancelada.', lnota; end if; return new;end;$tr_in_item$ language plpgsql;

-- exclui a triggerdrop trigger tr_in_item on item;

create trigger tr_in_item before insert on item for each row execute procedure tr_in_item();

listagem 5. trigger para o oracle

create or replace trigger tr_in_item before insert on item for each rowdeclare ltotalitens integer; lnota integer;begin -- seleciona o código da nota que está sendo incluída. lnota := :new.idnota; -- totaliza a quantidade de itens já cadastrados na nota. select count(*) into ltotalitens from item where idnota = lnota; -- verifica se existem mais do que 30 itens na nota. if (ltotalitens > 30) then raise_application_error(-20000,'a nota ' || :new.idnota || ' já está cheia. inclusão cancelada.'); end if;end;

3.    principais diferenças

1)   recompilação da trigger

quando vamos compilar uma trigger o banco de dados deve excluir a versão anterior caso ela já tenha sido compilada alguma vez. para isto, no oracle e no postgres basta usar a declaração create or replace, já no sql server é necessário verificar se já existe no dicionário um objeto com o mesmo nome da trigger, e caso exista é explicitamente excluída a trigger com a instrução abaixo:

if object_id ('tr_in_item','tr') is not null drop trigger tr_in_item

o sql server também tem outra forma de atualizar uma trigger usando a instrução alter trigger. neste exemplo a declaração da trigger começaria assim:

alter trigger tr_in_item on item

after insert

a vantagem da instrução create or replace do oracle e do postgres é que se a trigger não existe ela é criada, e já existindo ela é alterada.

Page 4: Desenvolvendo Triggers Em SQL

2)   declaração de variáveis locais

para o sql server o nome das variáveis locais deve sempre iniciar com uma arroba (@).

outro detalhe importante é que os tipos de dados de cada sgbd podem ser diferentes como varchar(sql server) e varchar2(oracle).

3)   acesso aos dados alterados

nas triggers existe um conceito importante para realizarmos críticas e procedimentos de controle: o acesso ao valor anterior e ao valor posterior de uma coluna no momento em que a trigger foi disparada.para termos acesso a estas informações no firebird e postgres, basta acrescentar o prefixo old para consultar o valor anterior e new para o novo valor. no oracle é similar, porém os prefixos são :old e :new.no sql server já é bem diferente, existem duas tabelas: inserted e deleted. como o nome diz em todas as inserções os dados serão carregados na tabela inserted, assim como nas exclusões todos os dados estão armazenados na tabela deleted. para as atualizações (update) o sql server considera como se ocorresse uma exclusão seguida de uma inclusão, portanto os valores anteriores estão na tabela deleted e os novos valores estão na tabela inserted.para realizarmos procedimentos que usem estas tabelas, ou consultamos diretamente elas ou carregamos os valores em variáveis locais, como foi feito no exemplo deste artigo: select @lnota = idnota from inserted;

4)   atribuição de variáveis no select

quando selecionamos o conteúdo de uma ou mais tabelas e queremos usar o resultado da consulta em procedimentos posteriores a consulta, devemos carregar o resultado dela em variáveis locais da trigger, nesta situação cada sgbd tratou de uma forma:

4.1.               sql server select @ltotalitens = count(*)

from item where idnota = @lnota;

4.2.               firebird select count(*)

from item where idnota = :lnota into :ltotalitens;

4.3.               postgres select into ltotalitens count(*) from item where idnota = lnota;

4.4.               oracle select count(*) into ltotalitens from item where idnota = lnota;

5)   mensagens

quando em uma trigger é necessário retornar alguma mensagem para a aplicação, teremos formas diferentes nos sgbd

Page 5: Desenvolvendo Triggers Em SQL

5.1 sql server

no sql server existe uma procedure que permite passarmos parâmetros para o texto, no nosso exemplo o código da nota é substituído na mensagem na posição onde temos a string “%d” que indica um parâmetro do tipo inteiro.

raiserror('a nota %d já está cheia. inclusão cancelada.',16,1,@lnota);

5.2 firebird

no firebird criamos uma exceção que no nosso exemplo chamamos de nota_cheia, depois chamamos ela no corpo da trigger através do comando exception.

create exception nota_cheia 'a nota já está cheia. inclusão cancelada.';exception nota_cheia;

5.3 postgres

o postgres tem uma forma similar de tratar as mensagens ao sql server, tem o comando raise exception que permite colocarmos parâmetros na mensagem.

raise exception 'a nota % já está cheia. inclusão cancelada.', lnota;

5.4 oracle

para o oracle concatenamos o código da nota no meio da mensagem para termos o mesmo efeito do sql server e o postgres. o primeiro parâmetro da procedure é o código de erro, sendo que se for do número -20000 ao -20999 indica uma mensagem texto.

raise_application_error(-20000,'a nota ' || :new.idnota || ' já está cheia. inclusão cancelada.');

6)   declaração da trigger no postgres

a declaração da trigger no postgres é bem diferente dos outros sgbd.primeiro definimos um procedimento com o corpo da trigger:

create or replace function tr_in_item() returns trigger as $tr_in_item$

e no final associamos este procedimento com a trigger através do código plpgsql:

$tr_in_item$ language plpgsql;

-- exclui a triggerdrop trigger tr_in_item on item;

create trigger tr_in_item before insert on item for each row execute procedure tr_in_item();

conclusões

neste artigo vimos diferenças básicas que devem ser tratadas quando pretendemos usar triggers para colocarmos as regras de negócio da aplicação em diversos sgbd.existem outras tantas diferenças que devem ser consideradas, a idéia do artigo foi somente tentar mostrar que ao criarmos procedimentos e funções para colocarmos as regras do negócio no banco de dados, iremos nos deparar com linguagens bem diferentes e nos obrigando a termos fontes distintos, que sofrerão manutenção

Page 6: Desenvolvendo Triggers Em SQL

independente.