Auto incremento

Firebird

02/12/2006

Olá amigos, boa noite

Preciso da ajuda de vocês com uma questão sobre autoincremento
A situação é a seguinte , criei um trigger para calcular o campo codcli e fazer seu autoincremento , segue p código da trigger e do generator:

create generator inc_codcli;


create trigger tb_Cliente for cliente
active before insert position 0
as
begin
if (new.codcli is null) then
new.codcli = gen_id (inc_codcli,1);
end


Está funcionando PERFEITAMENTE, faz exatamente o que deveria. A minha dúvida é sobre o seguinte:

Imaginemos que eu tenha 10 registros na tabela e delete 3 deles, quando eu inserir um novo ele será o codcli 11 pois o generator está setado para 11, como fazer o generator verificar o maior valor do campo códcli e receber este valor para que ao rodar a trigger o codigo seja corretamente o valor 8?

Obrigado a todos desde já


Zoom

Zoom

Curtidas 0

Respostas

Emerson Nascimento

Emerson Nascimento

02/12/2006

crieo que nesse caso você não poderá trabalhar com generator´s. terá de fazer a coisa na mão:
create trigger tb_Cliente for cliente
active before insert position 0
as
begin
if (new.codcli is null) then
new.codcli = (select coalesce(max(codcli),0)+1 from tb_Cliente);
end
assim o generator nem será necessário, podendo até ser ´dropado´


GOSTEI 0
Martins

Martins

02/12/2006

Desculpem eu meter minha colher aqui, pois sou um mero aprendiz professores, mas não corre o risco de gerar um código que já existe?

Tipo.
ID_CLI  NOME_CLI
1           MARIA
2           JOAO
3           MARCOS
4           AURÉLIO
5           JONAS
6           THIAGO
//
Se eu deletar os três últimos registros e depois incrementar novamente vai dar certo, mas se eue deletar digamos (2, 4 e 5) eu terei ficado com 03 (três) registros não é isso, então incrementando novamente apartir do maior código existente que seria o 06 (seis) eu teria (7,...) não seria isso?
Se não for assim, podem me explicar como funcionaria então, pq isso é interessante, não deixar brechas na sequencia númerica dos códigos.

valew!!



GOSTEI 0
Emerson Nascimento

Emerson Nascimento

02/12/2006

Martins, da forma como eu passei esse risco não existe, porque a instrução trará o maior valor de registro acrescido de 1, então, se você excluiu os registros 2, 4 e 5, ainda assim o novo registro gerado seria o 7, pois seria o maior (6) acrescido de 1.

mas o que o Martins mostrou é um caso muito comum. Quando houver exclusão de registros intermediários, ficará, sim, uma ´brecha´ entre os registros.

e, pra falar a verdade, eu nunca entendi muito porque a preocupação com o ID gerado para os registros. ele deveria ter usado internamente, transparente ao usuário.


GOSTEI 0
Martins

Martins

02/12/2006

Martins, da forma como eu passei esse risco não existe, porque a instrução trará o maior valor de registro acrescido de 1, então, se você excluiu os registros 2, 4 e 5, ainda assim o novo registro gerado seria o 7, pois seria o maior (6) acrescido de 1. mas o que o Martins mostrou é um caso muito comum. Quando houver exclusão de registros intermediários, ficará, sim, uma ´brecha´ entre os registros. e, pra falar a verdade, eu nunca entendi muito porque a preocupação com o ID gerado para os registros. ele deveria ter usado internamente, transparente ao usuário.


Ok [b:126b8f3738]Emerson.en[/b:126b8f3738], entendi agora meu amigo e concordo com vc quanto ao ID.

valew


GOSTEI 0
Martins

Martins

02/12/2006

Martins, da forma como eu passei esse risco não existe, porque a instrução trará o maior valor de registro acrescido de 1, então, se você excluiu os registros 2, 4 e 5, ainda assim o novo registro gerado seria o 7, pois seria o maior (6) acrescido de 1. mas o que o Martins mostrou é um caso muito comum. Quando houver exclusão de registros intermediários, ficará, sim, uma ´brecha´ entre os registros. e, pra falar a verdade, eu nunca entendi muito porque a preocupação com o ID gerado para os registros. ele deveria ter usado internamente, transparente ao usuário.


Ok [b:089dc51585]Emerson.en[/b:089dc51585], entendi agora meu amigo e concordo com vc quanto ao ID.

valew


GOSTEI 0
Martins

Martins

02/12/2006

Martins, da forma como eu passei esse risco não existe, porque a instrução trará o maior valor de registro acrescido de 1, então, se você excluiu os registros 2, 4 e 5, ainda assim o novo registro gerado seria o 7, pois seria o maior (6) acrescido de 1. mas o que o Martins mostrou é um caso muito comum. Quando houver exclusão de registros intermediários, ficará, sim, uma ´brecha´ entre os registros. e, pra falar a verdade, eu nunca entendi muito porque a preocupação com o ID gerado para os registros. ele deveria ter usado internamente, transparente ao usuário.


Ok [b:d0c684b3ad]Emerson.en[/b:d0c684b3ad], entendi agora meu amigo e concordo com vc quanto ao ID.

valew


GOSTEI 0
Adriano_servitec

Adriano_servitec

02/12/2006

Olah Emerson, tentei criar uma Trigger assim como vc postou no IBExpert, mais nao gera da erro de script

CREATE TRIGGER CORRENTE_BI0 FOR CORRENTE
ACTIVE BEFORE INSERT POSITION 0
as
begin 
if (new.sequencia2 is null) then
new.sequencia2 = (select coalesce(max(sequencia2),0)+1 from CORRENTE_BI0);
end


Nao pode criar esta nova trigger no before insert do ibexpert?


GOSTEI 0
Emerson Nascimento

Emerson Nascimento

02/12/2006

CREATE TRIGGER CORRENTE_BI0 FOR CORRENTE
ACTIVE BEFORE INSERT POSITION 0
as
begin
if (new.sequencia2 is null) then
new.sequencia2 = (select coalesce(max(sequencia2),0)+1 from CORRENTE);
end
note que havia um erro na instrução [i:498be7ccf0]select[/i:498be7ccf0]


GOSTEI 0
Adriano_servitec

Adriano_servitec

02/12/2006

Desculpe a percistencia Emerson, mais nao consegui fazer funcionar
CREATE TRIGGER CORRENTE_BI0 FOR CORRENTE
ACTIVE BEFORE INSERT POSITION 0
AS
begin
  /* Trigger text */
  if (new.sequencia2 is null) then 
new.sequencia2 = (select coalesce(max(sequencia2),0)+1 from CORRENTE); 

end

Erro
Column does not belong to referenced table. Dynamic SQL Error. SQL error code = -206. Subselect illegal in this context.


Bom eu criei este campo chamado [b:0be7c4e944]sequencia2[/b:0be7c4e944] como integer e na aba trigger da tabela dentro do ibexpert no before insert usei a opçao [b:0be7c4e944]New Trigger[/b:0be7c4e944] e coloquei o script do SQL e depois na hora que clico em [b:0be7c4e944]compiler trriger[/b:0be7c4e944] gera o erro acima.


GOSTEI 0
Emerson Nascimento

Emerson Nascimento

02/12/2006

ops!!! realmente havia um erro... :oops:

tente assim:
CREATE TRIGGER CORRENTE_BI FOR CORRENTE
ACTIVE BEFORE INSERT POSITION 0
AS
DECLARE VARIABLE NOVASEQUENCIA INTEGER;
BEGIN
  IF (NEW.SEQUENCIA2 IS NULL) THEN
  BEGIN
    SELECT COALESCE(MAX(SEQUENCIA2),0)+1
    FROM CORRENTE INTO :NOVASEQUENCIA;

    NEW.SEQUENCIA2 = NOVASEQUENCIA;
  END
END



GOSTEI 0
Adriano_servitec

Adriano_servitec

02/12/2006

Descobri como eh o correto

AS
begin
  /* Trigger text */
  if (new.sequencia2 is null) then 
  select coalesce(max(sequencia2),0)+1 from CORRENTE into new.sequencia2;

end



GOSTEI 0
Adriano_servitec

Adriano_servitec

02/12/2006

Olah Emerson, agora me surgiu uma duvida, eu postei se ter visto o teu post praticamente eh o mesmo codigo que eu postei com exeçao que foi declarada uma variavel [b:25fee2ed8d]DECLARE VARIABLE NOVASEQUENCIA INTEGER; [/b:25fee2ed8d]

Entao novamente a pergunta

O que eu fiz NAO esta correto?

Lembrando que nao conheço quase nada ainda de trigger


GOSTEI 0
Emerson Nascimento

Emerson Nascimento

02/12/2006

o que você postou está correto.
é que eu tenho costume de trabalhar com variáveis, por conta de geralmente fazer mais de uma avaliação com o valor obtido.


GOSTEI 0
Adriano_servitec

Adriano_servitec

02/12/2006

o que você postou está correto. é que eu tenho costume de trabalhar com variáveis, por conta de geralmente fazer mais de uma avaliação com o valor obtido.


Valeu amigo, muito obrigado.

Andei fazendo uns testes aki

Bom primeiro zerei o banco de dados pois a sequencia estava pegado o ultimo do generator, ai fiz uns lançamentos com a nova trriger e ficou na sequencia

1
2
3

ai exclui a sequenca 2
e fiz outro lançamento e ficou assim
1
3
4

a pergunta eh teria como voltar a ficar assim
1
2
3

em vez de
1
3
4

Ou no caso tem algum problema em fazer um retocesso na trigger pois no caso ai o que eh sequencia 3 passa a ser sequencia 2. Nao sei se pode fazer isso sem afetar o banco.

Lembrando que esse campo nao eh nem chave primaria nem chave estrangeira, uso apenas para fazer alguns updates e delete por ele.


GOSTEI 0
Emerson Nascimento

Emerson Nascimento

02/12/2006

tem sim. faça uma trigger after delete:
CREATE TRIGGER CORRENTE_DEL FOR CORRENTE
ACTIVE AFTER DELETE POSITION 0
AS
BEGIN
  UPDATE CORRENTE SET SEQUENCIA2 = SEQUENCIA2 - 1
  WHERE SEQUENCIA2 > OLD.SEQUENCIA2;
END

obs.:para tornar a execução mais rápida - tanto dessa trigger quanto da anterior - crie um índice pelo campo sequencia2


GOSTEI 0
Adriano_servitec

Adriano_servitec

02/12/2006

tem sim. faça uma trigger after delete:
CREATE TRIGGER CORRENTE_DEL FOR CORRENTE
ACTIVE AFTER DELETE POSITION 0
AS
BEGIN
  UPDATE CORRENTE SET SEQUENCIA2 = SEQUENCIA2 - 1
  WHERE SEQUENCIA2 > OLD.SEQUENCIA2;
END
obs.:para tornar a execução mais rápida - tanto dessa trigger quanto da anterior - crie um índice pelo campo sequencia2


Olah Emerson, testei aqui e desta forma deleta todos os registros posteriores tipo se eu tiver assim
1
2
3

e deletar a sequencia 2
fica soh o 1
ou seja deleta o 2 e o 3 e assim por diante

eu uso para deletar assim
if edit4.Text = ´´ then begin
    raise Exception.Create(´É necessário selecionar a Linha na Grade para Excluir´);
end else
if application.messagebox(Pchar(´Deseja Excluir este Lançamento:´ + #13+ dm.qrylimpa.FieldByName(´Sequencia´).AsString +´  ´+ 13+ dm.qrylimpa.FieldByName(´associado´).AsString), Pchar(´Excluir Dados´+Self.Caption), MB_ICONQUESTION
+ MB_YESNO) = IDYES then begin

with dm.qrylimpa do begin
    Close;
    SQL.Clear;
    sql.text := ´delete from corrente where sequencia = :vExclui´;
    ParamByName(´vExclui´).Value :=vExclui;

    try
      ExecSQL;
      dm.tlimpa.commit;
      dm.qrylimpa.close;
      dm.qrylimpa.sql.clear;
      dm.qrylimpa.sql.text := ´select * from corrente where matricula = :matricula´;
      dm.qrylimpa.Open;
      sbar.SimpleText := ´Linha Excluída...´;
    except
      On E:Exception do begin
        dm.ibt2.Rollback;
        dm.tlimpa.Rollback;
        sbar.SimpleText := ´Abortado...´;
        Showmessage(´Falha na Exclusão dos Dados!´#1310´Mensagem: ´+E.Message);
      end;

    end;

  end;
end;


como uso o dbgrid para excluir fiz este codigo aqui tambem
procedure TForm6.DBGrid1CellClick(Column: TColumn);
begin
vexclui:=dm.qrylimpa.fieldbyname(´sequencia´).asinteger;
edit4.text:=inttostr(vExclui);

end;


Outra coisa amigo, como crio indice neste campo SEQUENCIA2

Obrigado mais uma vez por me ajudar.


GOSTEI 0
Emerson Nascimento

Emerson Nascimento

02/12/2006

[quote:b6f2def0a7=´emerson.en´]tem sim. faça uma trigger after delete:
CREATE TRIGGER CORRENTE_DEL FOR CORRENTE
ACTIVE AFTER DELETE POSITION 0
AS
BEGIN
  UPDATE CORRENTE SET SEQUENCIA2 = SEQUENCIA2 - 1
  WHERE SEQUENCIA2 > OLD.SEQUENCIA2;
END
obs.:para tornar a execução mais rápida - tanto dessa trigger quanto da anterior - crie um índice pelo campo sequencia2


Olah Emerson, testei aqui e desta forma deleta todos os registros posteriores tipo se eu tiver assim
1
2
3

e deletar a sequencia 2
fica soh o 1
ou seja deleta o 2 e o 3 e assim por diante

eu uso para deletar assim
if edit4.Text = ´´ then begin
    raise Exception.Create(´É necessário selecionar a Linha na Grade para Excluir´);
end else
if application.messagebox(Pchar(´Deseja Excluir este Lançamento:´ + #13+ dm.qrylimpa.FieldByName(´Sequencia´).AsString +´  ´+ 13+ dm.qrylimpa.FieldByName(´associado´).AsString), Pchar(´Excluir Dados´+Self.Caption), MB_ICONQUESTION
+ MB_YESNO) = IDYES then begin

with dm.qrylimpa do begin
    Close;
    SQL.Clear;
    sql.text := ´delete from corrente where sequencia = :vExclui´;
    ParamByName(´vExclui´).Value :=vExclui;

    try
      ExecSQL;
      dm.tlimpa.commit;
      dm.qrylimpa.close;
      dm.qrylimpa.sql.clear;
      dm.qrylimpa.sql.text := ´select * from corrente where matricula = :matricula´;
      dm.qrylimpa.Open;
      sbar.SimpleText := ´Linha Excluída...´;
    except
      On E:Exception do begin
        dm.ibt2.Rollback;
        dm.tlimpa.Rollback;
        sbar.SimpleText := ´Abortado...´;
        Showmessage(´Falha na Exclusão dos Dados!´#1310´Mensagem: ´+E.Message);
      end;

    end;

  end;
end;


como uso o dbgrid para excluir fiz este codigo aqui tambem
procedure TForm6.DBGrid1CellClick(Column: TColumn);
begin
vexclui:=dm.qrylimpa.fieldbyname(´sequencia´).asinteger;
edit4.text:=inttostr(vExclui);

end;


Outra coisa amigo, como crio indice neste campo SEQUENCIA2

Obrigado mais uma vez por me ajudar.[/quote:b6f2def0a7]
não procede. o código que eu te passei não apaga nada. simplesmente atualiza os registros.
uma dica: as linhas onde há sql.clear são totalmente desnecessárias no seu código.

veja se a exclusão não de dá por outro motivo.


GOSTEI 0
Adriano_servitec

Adriano_servitec

02/12/2006

Nada, nao cosegui ainda

Eu chegue ateh a mudar o where pra ver se dava certo, ai fiz assim

AS
begin
/* Trigger text */
UPDATE CORRENTE SET SEQUENCIA = SEQUENCIA - 1
WHERE SEQUENCIA <> OLD.SEQUENCIA;

end
Estava assim
1
2
3
4
deletei o 3
Nesta forma ficou assim
-1
0


Ainda nao consegui fazer o certo


GOSTEI 0
Emerson Nascimento

Emerson Nascimento

02/12/2006

sequencia? não era sequencia2 ?!?!?!?!? o campo sequencia não poderá ser usado, pois é nele que você se baseia para fazer a exclusão do registro (usado no where). dessa forma, o mecanismo do banco de dados ´se perde´.

tente colocar mais um campo na sua instrução de exclusão.

delete from corrente where sequencia = :vExclui and [qualquer outra condição]


GOSTEI 0
Adriano_servitec

Adriano_servitec

02/12/2006

sequencia? não era sequencia2 ?!?!?!?!? o campo sequencia não poderá ser usado, pois é nele que você se baseia para fazer a exclusão do registro (usado no where). dessa forma, o mecanismo do banco de dados ´se perde´. tente colocar mais um campo na sua instrução de exclusão. delete from corrente where sequencia = :vExclui and [qualquer outra condição]


Entao nao pode ser o campo sequencia? Eu tinha criado o campo sequencia2, mais como me baseio pelo campo sequenca acehi melhor usar as trigger criadas acima no campo sequencia da tabela corrente.


tente colocar mais um campo na sua instrução de exclusão. delete from corrente where sequencia = :vExclui and [qualquer outra condição]
O que vc sujere aqui (nao entendi o que mais devo colocar na condiçao do where), isto eh se tiver como usar o campo sequencia para atualizar a tabela usando o update.


GOSTEI 0
Adriano_servitec

Adriano_servitec

02/12/2006

Esqueçe tudo amigo, ja foi resolvido o problema, eu continuei insistindo no sequencia que eh o campo que serve de base para tudo.

Lembra la no começo que tu me disse assim:

obs.:para tornar a execução mais rápida - tanto dessa trigger quanto da anterior - crie um índice pelo campo sequencia2
Pois eh nao sabia como ia criar este indices, ai lendo uma apostila descobri como criar o indice,ae criei um indice chamado [b:7202feb583]CORRENTE_IDX1[/b:7202feb583] e coloquei o campo sequencia como indice.

No mais soh faltava isso mesmo, por isso que estava bagunçando o trigger :D

Do mais os codigos acima sao os mesmo que vc me passou soh com a mudança dos campos sequenca2 para sequencia.

Bom amigo, agora sim esta como eu queria. 100¬ perfeito

Mais uma vez agradeço sua paciencia e ajuda nesta duvida.

Pra mim caso encerrado, soh nao sei pro amigo dono do post que postou a duvida. :?:

Me desculpe por ter invadido o teu post com minhas duvidas. :oops:

Valeu ai Emerson


GOSTEI 0
POSTAR