Como usar Trigger?
Pessoal ainda nao testei, estou querendo aprender a usar as trigger, entao fiz essa trigger
A ideia eh para criar uma restriçao aonde nao pode incluir valores nulos no campo valor da tabela, a restricao ja criei no [b:f22e41ee56]Exception[/b:f22e41ee56] do IBExpert, entao gostaria de saber se esta certo essa Trigger?
Agradeço a opniao de todos.
Adriano.
[b:f22e41ee56][color=blue:f22e41ee56]E tambem se puderem me explicar, se eh melhor usar trigger, em vez de usar codigos dentro da unit do delphi! Ou seja eu posso muito bem fazer um codigo de restriçao no evento onexit do componente, mais gostaria da opnião do pessoal, se eh mais vantajoso usar na trigger ou no programa mesmo.[/color:f22e41ee56][/b:f22e41ee56]
Abçs;
SET SQL DIALECT 3; SET NAMES ISO8859_1; SET TERM ^ ; CREATE TRIGGER RESTRICAOVALORTBCONTA FOR TBCONTA ACTIVE BEFORE INSERT POSITION 0 AS begin /* Trigger Para nao ficar valor null*/ if (Exists(Select * from tbconta where valor = ´´) ) then Exception RESTRICAO ´O campo valor nao pode ficar em branco´; end ^ SET TERM ; ^
A ideia eh para criar uma restriçao aonde nao pode incluir valores nulos no campo valor da tabela, a restricao ja criei no [b:f22e41ee56]Exception[/b:f22e41ee56] do IBExpert, entao gostaria de saber se esta certo essa Trigger?
Agradeço a opniao de todos.
Adriano.
[b:f22e41ee56][color=blue:f22e41ee56]E tambem se puderem me explicar, se eh melhor usar trigger, em vez de usar codigos dentro da unit do delphi! Ou seja eu posso muito bem fazer um codigo de restriçao no evento onexit do componente, mais gostaria da opnião do pessoal, se eh mais vantajoso usar na trigger ou no programa mesmo.[/color:f22e41ee56][/b:f22e41ee56]
Abçs;
Adriano_servitec
Curtidas 0
Respostas
Sremulador
10/01/2007
primeiramente crei isto
depois ajuste o gatilho
os gatilhos são como ações assim como ocorre no delphi, tipo onclick, onexit, assim vai, neste caso são antes de inserir, depois, antes de exluir depois, antes de alterar e depois
CREATE EXCEPTION RESTRICAO´CAMPO NÃO PODE SER NULO´;
depois ajuste o gatilho
CREATE TRIGGER RESTRICAOVALORTBCONTA FOR TBCONTA ACTIVE BEFORE INSERT POSITION 0 AS begin /* Trigger Para nao ficar valor null*/ if (Exists(Select * from tbconta where valor is null ) then Exception RESTRICAO; end
os gatilhos são como ações assim como ocorre no delphi, tipo onclick, onexit, assim vai, neste caso são antes de inserir, depois, antes de exluir depois, antes de alterar e depois
GOSTEI 0
Adriano_servitec
10/01/2007
Obrigado por me ajudar [b:9c0cbb9b8f]sremulador[/b:9c0cbb9b8f]
O mesmo se aplica para esta ação tambem sremulador?
O mesmo se aplica para esta ação tambem sremulador?
ALTER TRIGGER UNIQSEQCONTA ACTIVE BEFORE INSERT POSITION 0 AS begin if ( Exists(Select * from tbconta WHERE sequencia = NEW.sequencia ) ) then Exception RESTRICAO ´Campo Matrícula Já Existe!´; end
GOSTEI 0
Sremulador
10/01/2007
Amigo os exceptions voc^?e cria apenas uma vez, e utiliza apenas o nome
No caso de seu select não haveria ´Acho´ do * já que e uma comparação sem pegar resultados para um terceiro tratamento, assim ficará mais rapido a ação...
ALTER TRIGGER UNIQSEQCONTA ACTIVE BEFORE INSERT POSITION 0 AS begin if ( Exists(Select * from tbconta WHERE sequencia = NEW.sequencia ) ) then Exception RESTRICAO; end
No caso de seu select não haveria ´Acho´ do * já que e uma comparação sem pegar resultados para um terceiro tratamento, assim ficará mais rapido a ação...
GOSTEI 0
Adriano_servitec
10/01/2007
Amigo os exceptions voc^?e cria apenas uma vez, e utiliza apenas o nome
Sim eu criei somente uma vezCREATE EXCEPTION RESTRICAO ´´;
No caso de seu select não haveria ´Acho´ do * já que e uma comparação sem pegar resultados para um terceiro tratamento, assim ficará mais rapido a ação...
Entao em vez de usar *(curinga para todos) o certo seria somente o campo que faz a restrição?Valeu amigo.
GOSTEI 0
Emerson Nascimento
10/01/2007
creio que o correto seria:
CREATE TRIGGER RESTRICAOVALORTBCONTA FOR TBCONTA ACTIVE BEFORE INSERT POSITION 0 AS begin /* Trigger Para nao ficar valor null*/ if (NEW.VALOR IS NULL) then Exception RESTRICAO; end
GOSTEI 0
Adriano_servitec
10/01/2007
creio que o correto seria:
Entao nao preciso fazer um select? eh soh usar assim como vc postou amigo? e esse outro que eu fiz para ser um unique, tambem devo modificar?CREATE TRIGGER RESTRICAOVALORTBCONTA FOR TBCONTA ACTIVE BEFORE INSERT POSITION 0 AS begin /* Trigger Para nao ficar valor null*/ if (NEW.VALOR IS NULL) then Exception RESTRICAO; end
AS begin if ( Exists(Select * from tbconta WHERE sequencia = NEW.sequencia ) ) then Exception RESTRICAO; end
GOSTEI 0
Sremulador
10/01/2007
Realmente nãp prestei atenção, se for na mesma tabela não, mas se for em outra tabela você teria que fazer o select...
GOSTEI 0
Sremulador
10/01/2007
Mas outra forma de fazer isso e setando o campo para não aceitar valor nulo..., a diferença e que não vai exibir a mensagem personalizada...
GOSTEI 0
Adriano_servitec
10/01/2007
Obrigado pessoal, agora ja estou entendendo.
Mais uma pergunta essas triger ela dispara somente na hora em que vou gravar no banco ou tem como disparar antes? Como faço no evento onexit dentro do delphi.
Ainda mais uma pergunta: Tenho uma tabela com campos assim
tabmovimento
sequencia
conta
descricao
valor
e outra tabdebido(tabela filha)
sequencia (FK) (Refernecia com a tabela tabmovimento)
conta_D
descricao
valor
E na hora em que eu for gravar no form vai gravar na tabmovimento o que eu digitar no form, a pergunta seria como posso gravar tambem os mesmos dados na tabela (filha)? Preciso ao mesmo tempo fazer um codigo para as duas tabelas tipo assim
insert into tabmovimento
....
parambyname(´campos´).AsString:=editConta;
execsql
insert into tabdebito
...
parambyname(´campos´).AsString:=editConta;
execSQL
Ou tem como fazer somente em uma tabela e a outra ja receber o resultado?
Mais uma pergunta essas triger ela dispara somente na hora em que vou gravar no banco ou tem como disparar antes? Como faço no evento onexit dentro do delphi.
Ainda mais uma pergunta: Tenho uma tabela com campos assim
tabmovimento
sequencia
conta
descricao
valor
e outra tabdebido(tabela filha)
sequencia (FK) (Refernecia com a tabela tabmovimento)
conta_D
descricao
valor
E na hora em que eu for gravar no form vai gravar na tabmovimento o que eu digitar no form, a pergunta seria como posso gravar tambem os mesmos dados na tabela (filha)? Preciso ao mesmo tempo fazer um codigo para as duas tabelas tipo assim
insert into tabmovimento
....
parambyname(´campos´).AsString:=editConta;
execsql
insert into tabdebito
...
parambyname(´campos´).AsString:=editConta;
execSQL
Ou tem como fazer somente em uma tabela e a outra ja receber o resultado?
GOSTEI 0
Sremulador
10/01/2007
Mais uma pergunta essas triger ela dispara somente na hora em que vou gravar no banco ou tem como disparar antes? Como faço no evento onexit dentro do delphi.
Tem a opção Antes e Depois
Belfore Alfter
tabmovimento
sequencia
conta
descricao
valor
e outra tabdebido(tabela filha)
sequencia (FK) (Refernecia com a tabela tabmovimento)
conta_D
descricao
valor
E na hora em que eu for gravar no form vai gravar na tabmovimento o que eu digitar no form, a pergunta seria como posso gravar tambem os mesmos dados na tabela (filha)? Preciso ao mesmo tempo fazer um codigo para as duas tabelas tipo assim
insert into tabmovimento
....
parambyname(´campos´).AsString:=editConta;
execsql
insert into tabdebito
...
parambyname(´campos´).AsString:=editConta;
execSQL
Ou tem como fazer somente em uma tabela e a outra ja receber o resultado?
Diretamente no db somente /se um usuário estiver por vez, mas desconhece...
GOSTEI 0
Adriano_servitec
10/01/2007
Entao o melhro eh criar um Stored Procedure + ou - assim:
Supondo que a estrutura da tabela fosse:
Mestre
----------------
Codigo - Integer
Descricao - Varchar(50)
Data - Date
Detalhe
----------------
Cod_Mestre - Integer
Cod_Produto - Integer
Quantidade - Integer
Supondo que a estrutura da tabela fosse:
Mestre
----------------
Codigo - Integer
Descricao - Varchar(50)
Data - Date
Detalhe
----------------
Cod_Mestre - Integer
Cod_Produto - Integer
Quantidade - Integer
Set term ^ ; create procedure GravaDados( Cod_Mestre Integer, Desc_Mestre varchar(50), Data_Mestre Date, Cod_Produto Integer, Quantidade Integer ) as begin if ( not exists(select codigo from Mestre where codigo = :Cod_Mestre) )then Insert into Mestre Values ( Cod_Mestre, Desc_Mestre, Data_Mestre ); Insert into Detalhe Values (Cod_Mestre, Cod_Produto, Quantidade ); end ^ Set Term ; ^
GOSTEI 0
Adriano_servitec
10/01/2007
Bom a Stored Procedure jah esta criada
(Espero que esteja correta) :D
Agora entao se eu for usar query ou IBStoredProc terei que passar os parametros da SP que eu criei?
Tipo assim:
[b:8c9475a6ae]select * form GRAVADADOS (:SEQUENCIA, :CONTA, :HISTORICO, :VALOR, :CONTAD)[/b:8c9475a6ae]assim da erro [color=red:8c9475a6ae]procedure gravadados does not return any values delphi[/color:8c9475a6ae]
Usando um IBStoredProcedure da o sequinte erro: [color=red:8c9475a6ae]use execproc for procedure use tquery for select procedure delphi[/color:8c9475a6ae] Neste caso eu apontei a propriedade StoredProcName para GRAVADADOS , e apareçe os paramentro da propriedade parametes assim:
0-sequencia
1-conta
2-historico
3-valor
4-contad
O que esta errado pq nao consigo ativar nenhum dois dois modos?
Outra coisa
Pq o que eu quero que essa Stored procedure faça eh incluir dois lançamentos (alias serah 3 lançamentos de uma soh vez, ou seja vai incluir na tabela movimento, debito e credito de uma soh vez).
Grato a ajuda de todos.
Adriano.
(Espero que esteja correta) :D
SET TERM ^ ; CREATE PROCEDURE GRAVADADOS ( SEQUENCIA INTEGER, CONTA VARCHAR(15), HISTORICO VARCHAR(100), VALOR NUMERIC(15,2), CONTAD VARCHAR(15)) AS begin if ( not exists(select * from tbconta where sequencia = :sequencia) ) then Insert Into tbconta (sequencia, conta, historico, valor) Values (:sequencia, :conta, :historico, :valor); Insert into debito (sequencia, contad, historico, valor) Values ( :sequencia, :contad, :historico, :valor ); Suspend; end^ SET TERM ; ^ GRANT SELECT,INSERT ON TBCONTA TO PROCEDURE GRAVADADOS; GRANT INSERT ON DEBITO TO PROCEDURE GRAVADADOS; GRANT EXECUTE ON PROCEDURE GRAVADADOS TO SYSDBA;
Agora entao se eu for usar query ou IBStoredProc terei que passar os parametros da SP que eu criei?
Tipo assim:
[b:8c9475a6ae]select * form GRAVADADOS (:SEQUENCIA, :CONTA, :HISTORICO, :VALOR, :CONTAD)[/b:8c9475a6ae]assim da erro [color=red:8c9475a6ae]procedure gravadados does not return any values delphi[/color:8c9475a6ae]
Usando um IBStoredProcedure da o sequinte erro: [color=red:8c9475a6ae]use execproc for procedure use tquery for select procedure delphi[/color:8c9475a6ae] Neste caso eu apontei a propriedade StoredProcName para GRAVADADOS , e apareçe os paramentro da propriedade parametes assim:
0-sequencia
1-conta
2-historico
3-valor
4-contad
O que esta errado pq nao consigo ativar nenhum dois dois modos?
Outra coisa
IBStoredProc deve ser usado para Procedures executáveis, para SELECT procedures use um IBQuery.
No caso essa Stored Procedure que eu criei, se aplica em qual caso segundo esse quote acima? Pq o que eu quero que essa Stored procedure faça eh incluir dois lançamentos (alias serah 3 lançamentos de uma soh vez, ou seja vai incluir na tabela movimento, debito e credito de uma soh vez).
Grato a ajuda de todos.
Adriano.
GOSTEI 0
Emerson Nascimento
10/01/2007
vc deve usar, numa query:
EXECUTE PROCEDURE GRAVADADOS (:SEQUENCIA, :CONTA, :HISTORICO, :VALOR, :CONTAD)
e chamar o método Execute (ou similar). nesse caso não se usa open.
no IBStoredProcedure você deve apenas preencher os parâmetros e executá-la. outra coisa: não sei se tem influência no erro, mas, como sua SP não retorna dados, o [i:ceaaea2395]Suspend[/i:ceaaea2395] é desnecessário.
EXECUTE PROCEDURE GRAVADADOS (:SEQUENCIA, :CONTA, :HISTORICO, :VALOR, :CONTAD)
e chamar o método Execute (ou similar). nesse caso não se usa open.
no IBStoredProcedure você deve apenas preencher os parâmetros e executá-la. outra coisa: não sei se tem influência no erro, mas, como sua SP não retorna dados, o [i:ceaaea2395]Suspend[/i:ceaaea2395] é desnecessário.
GOSTEI 0
Emerson Nascimento
10/01/2007
outra coisa: creio que falta um begin/end na SP:
obs.: na verdade somente ponha o begin/end se as duas instruções insert forem casadas (executadas juntas)
CREATE PROCEDURE GRAVADADOS ( SEQUENCIA INTEGER, CONTA VARCHAR(15), HISTORICO VARCHAR(100), VALOR NUMERIC(15,2), CONTAD VARCHAR(15)) AS begin if ( not exists(select sequencia from tbconta where sequencia = :sequencia) ) then begin Insert Into tbconta (sequencia, conta, historico, valor) values (:sequencia, :conta, :historico, :valor); Insert into debito (sequencia, contad, historico, valor) values ( :sequencia, :contad, :historico, :valor ); end; -- Suspend; end^
GOSTEI 0
Adriano_servitec
10/01/2007
vc deve usar, numa query:
EXECUTE PROCEDURE GRAVADADOS (:SEQUENCIA, :CONTA, :HISTORICO, :VALOR, :CONTAD)
e chamar o método Execute (ou similar). nesse caso não se usa open.
no IBStoredProcedure você deve apenas preencher os parâmetros e executá-la. outra coisa: não sei se tem influência no erro, mas, como sua SP não retorna dados, o [i:eab27f7f14]Suspend[/i:eab27f7f14] é desnecessário.
Soh mais uma pergunta Emerson, eu escrevo:
[b:eab27f7f14]EXECUTE PROCEDURE GRAVADADOS (:SEQUENCIA, :CONTA, :HISTORICO, :VALOR, :CONTAD)[/b:eab27f7f14] dentro da propriedade SQL? ou faço algo tipo assim num button que vou usar para incluir os dados:
with dm.QuerySProc do begin close; SQL.clear; sql.add(´EXECUTE PROCEDURE GRAVADADOS (:SEQUENCIA, :CONTA, :HISTORICO, :VALOR, :CONTAD)´); ExecSQL
obs.: na verdade somente ponha o begin/end se as duas instruções insert forem casadas (executadas juntas)
Sim elas sao casadas como vc disse ou seja vao fazer o mesmo processo de gravaçao de dados, inclusive vai ter mais outra tabela chamada credito que vai estar casada tambem com a tabela movimento(tabela mestre)[b:eab27f7f14]Obs:A StoredProcedure eu vou arrumar cfe. vc postou.[/b:eab27f7f14]
Desculpe por postar essas perguntas, mais realmente ainda nao sei usar Stored Procedure.
[color=blue:eab27f7f14]Sobre os compoentes IBStoredProc e IBQuery se possivel for prefiro usar o IBQuery.[/color:eab27f7f14]
Obrigado amigo.
GOSTEI 0
Sremulador
10/01/2007
vc pode utilizar os dois, não tera problemas...
GOSTEI 0
Adriano_servitec
10/01/2007
vc pode utilizar os dois, não tera problemas...
Olah sremulador, sobre a tua resposta se refere ao modo como eu chamo a StoredProcedure? Ou sobre o componente IBStoredProcedure e IBQuery?GOSTEI 0
Sremulador
10/01/2007
Os dois para a execução da procedure esta correta, não pode esquecer de passar os parametros,
Quando a Query vc pode utilizar sem problemas, aqui 99¬ são em querys...
Quando a Query vc pode utilizar sem problemas, aqui 99¬ são em querys...
GOSTEI 0
Adriano_servitec
10/01/2007
Os dois para a execução da procedure esta correta, não pode esquecer de passar os parametros,
Quando a Query vc pode utilizar sem problemas, aqui 99¬ são em querys...
Ufa ateh que enfim funcionou :D
Realmente agora aprendi que com apenas uma Stored Procedure eh o suficiente para o que eu preciso
O resultado final ficou assim entao:
if application.messagebox(PChar(´Deseja Gravar esta Nota?´), PChar(´Incluir Dados´+Self.Caption),MB_IConquestion +MB_YesNo)=IDYES then begin with dm.QStoredProc do begin close; SQL.clear; sql.add(´EXECUTE PROCEDURE GRAVADADOS (:SEQUENCIA, :CONTA, :HISTORICO, :VALOR, :CONTAD)´); ParamByName(´conta´).AsString:=e1.text; ParamByName(´historico´).AsString:=r1.text; svalor := stringreplace(e3.text, ´.´, ´´, [rfReplaceAll]); svalor := stringreplace(svalor, ´,´, ´.´, [rfReplaceAll]); ParamByName(´valor´).Value:=sValor; ParamByName(´contad´).asString:=e1.text; try ExecSQL;
Obrigado amigos agora ja estou começando a aprender um pouco mais sobre Trigger e Stored Procedure.
Valeu pessoal :D
Soh mais uma pergunta
[b:2df1d3cbde]Para que servem as UDFs[/b:2df1d3cbde]
GOSTEI 0
Adriano_servitec
10/01/2007
Agora me surgiu um outro problema: :cry:
Veja a IBQuery : Atençao sobre a linha em vermelho
A SP tambem mudei assim
Veja a IBQuery : Atençao sobre a linha em vermelho
if application.messagebox(PChar(´Deseja Gravar este Lançamento?´), PChar(´Incluir Dados´+Self.Caption),MB_IConquestion +MB_YesNo)=IDYES then
begin
with dm.QStoredProc do
begin
close;
SQL.clear;
sql.add(´EXECUTE PROCEDURE SP_GRAVACONTA (:SEQUENCIA, :CONTA, :HISTORICO, :VALOR, :CONTAD, :MES, :ANO, :DATA)´);
[color=red:90f410c9df]sql.add(´WHERE Extract(Month FROM DATA) = :mes and Extract(Year FROM DATA) = :ano´);[/color:90f410c9df]
ParamByName(´conta´).AsString:=e1.text;
ParamByName(´historico´).AsString:=r1.text;
svalor := stringreplace(e3.text, ´.´, ´´, [rfReplaceAll]);
svalor := stringreplace(svalor, ´,´, ´.´, [rfReplaceAll]);
ParamByName(´valor´).Value:=sValor;
ParamByName(´contad´).asString:=e1.text;
ParamByName(´mes´).value:=uppercase(formatdatetime(´MM´,(STRTODATE(edit5.TEXT))));
Parambyname(´ano´).asinteger := StrToInt(FormatDateTime(´YYYY´,StrToDate(Edit5.text)));
ParamByName(´data´).value:=edit5.text;
try
ExecSQL;
dm.tLconta.Active:=true;
dm.tLConta.Commit;
close;
sql.clear;
sql.add(´select * from tbconta´);
sql.add(´WHERE Extract(Month FROM DATA) = :mes and Extract(Year FROM DATA) = :ano´);
sql.add(´order by sequencia´);
Parambyname(´mes´).asinteger := StrToInt(FormatDateTime(´MM´,StrToDate(Edit5.text)));
Parambyname(´ano´).asinteger := StrToInt(FormatDateTime(´YYYY´,StrToDate(Edit5.text)));
open;
dm.Tbconta.FetchAll;
eNR.Caption := IntToStr(dm.tbconta.RecordCount);
except
on E:Exception do
begin
dm.tlconta.RollBack;
sbar.SimpleText:=´Abortado´;
ShowMessage(´Falha na Inclusão dos Dados!´#1310´ Mensagem: ´+E.Message);
end;
end;
end;
Esta gerando erro nesta linha em vermelho aonde quero uma condiçao feito no whereA SP tambem mudei assim
SET TERM ^ ; CREATE PROCEDURE SP_GRAVACONTA ( SEQUENCIA INTEGER, CONTA VARCHAR(15), HISTORICO VARCHAR(100), VALOR NUMERIC(15,2), MES VARCHAR(2), ANO VARCHAR(4), CONTAD VARCHAR(15), DATA DATE) AS begin if ( not exists(select * from tbconta where sequencia = :sequencia) ) then begin Insert Into tbconta ( sequencia, conta, historico, valor, mes, ano, DATA ) Values ( :sequencia, :conta, :historico, :valor, :mes, :ano, :DATA ); Insert into debito ( sequencia, contad, historico, valor, mes, ano, DATA ) Values ( :sequencia, :contad, :historico, :valor, :mes, :ano, :DATA ); end end^ SET TERM ; ^ GRANT SELECT,INSERT ON TBCONTA TO PROCEDURE SP_GRAVACONTA; GRANT INSERT ON DEBITO TO PROCEDURE SP_GRAVACONTA; GRANT EXECUTE ON PROCEDURE SP_GRAVACONTA TO SYSDBA;
GOSTEI 0
Emerson Nascimento
10/01/2007
o que exatamente você quer fazer?
GOSTEI 0
Adriano_servitec
10/01/2007
o que exatamente você quer fazer?
Eh o sequinte faço varios lançamentos, as vezes to no mes 01 as vezes no 02 e volto pro mes 01, entao assim que começo a lançar tenho um where no evento onexit de um edit para filtrar cfe o mes na dbgrid.
Pra dizer a verdade esta a maior bagunça a passagem destes parametros, nao esta obedeçendo o que esta no edit, maskedit, etc...
Nao estou entendendo pq se no edit5 esta a data tipo 31/01/2006 la no banco esta gravando no campo mes o numero da conta e no campo contaD o ano e no campo ano o mes. Nao estou entendendo o que esta aconteçendo.
:(
GOSTEI 0
Adriano_servitec
10/01/2007
Resolvido, tirei o campo CONTAD e coloquei somente CONTA na tabeal DEBITO e agora esta funcionando direitinho. Nao sei o pq mais funcionou. :D
Obrigado a todos, pela ajuda.
Obrigado a todos, pela ajuda.
GOSTEI 0