Generators no Firebird 1.5.1

Firebird

01/09/2004

Caros colegas,
Gostaria de efetuar o seguinte procedimento:
- Ao cadastrar um REgistro (Ex.: Filial), criar um Generator ,GEN_CLIFILXX, onde XX seria o código do Cadastro da Filial.

- Quando incluisse um novo cliente na Filial, seria utilizado esse Generator para Gerar o Código do Cliente
- Como seria criado uma Trigger no Insert do Cliente, dependendo da Filial seria um Generator diferente (Ex.: Filial 01 - GEN_CLIFIL01, Filial 02 - GEN_CLIFIL02, etc...)..
Para criar o Generator utilizei o seguinte código:
  insert into RDB$GENERATORS(RDB$GENERATOR_NAME, rdb$generator_id) Values(´GEN_CLIFILIAL´||new.Empresa
          ||´_´|| New.Filial,0);
 


Porém não consegui utilizar na função gen_id, ou melhor, não conseguo montar uma variável dinamicamente com o nome do generator para utilizar no gen_id

Isso é possivel no Firebird????

Agradeço qualquer ajuda....


Bolus

Bolus

Curtidas 0

Respostas

Bolus

Bolus

01/09/2004

Completando a Questão anterior....

a Criação e Utilização do Generator é para ser ativado/utilizado no proprio Servidor, através de Triggers e Stored Procedure, bem como zerar o Generator..
Apesar de no material do Firebird 1.5.1 informar o seguinte comando
  set generator XXXX to 9999;


onde XXXX - seria o nome do Generator
9999 - seria o numero a atribui ao generator.

Não consegui utilizar estes comando em uma Stored Procedure, tendo que utilizar o seguinte codigo
    iGEN = gen_id(Fatura,0) * -1; /* multiplicação por menos um */
    iGEn = gen_id(Fatura,iGEN); /* desta maneira zerei o generator Fatura */


Agradeço qualquer ajuda possivel....


GOSTEI 0
Fsflorencio

Fsflorencio

01/09/2004

É possível no Firebird 1.5.

Utilize a função EXECUTE STATEMENT

Você pode usar comandos DDL com esta função:

Ex:
Crie uma variável do tipo Varchar(1000) e outra Inteira (ou então use parâmetros da procedure para informar estes valores);

TEXTO VARCHAR(1000);
FILIAL INTEGER;

TEXTO = ´CREATE GENERATOR GEN_CLIFILIAL´ || CAST(FILIAL AS VARCHAR(1) );

EXECUTE STATEMENT TEXTO;

TEXTO = ´SET GENERATOR GEN_CLIFILIAL´ || CAST(FILIAL AS VARCHAR(1) ) || ´ TO 9999´;

EXECUTE STATEMENT TEXTO;

Você também pode obter resultados com a função execute statement:
Ex: retornar o maior código de filial da tabela empresas para criar os generators.

DECLARE VARIABLE RETORNO INTEGER;

texto = ´SELECT MAX(COD_FILIAL) FROM EMPRESAS´

EXECUTE STATEMENT TEXTO INTO :RETORNO;

RETORNO = RETORNO + 1;

TEXTO = ´CREATE GENERATOR GEN_CLIFILIAL´ || CAST(RETORNO AS VARCHAR(1) );//aqui concatena uma variável texto com uma inteira

EXECUTE STATEMENT TEXTO;

Acredito que isto deve resolver seu problema.


GOSTEI 0
Bolus

Bolus

01/09/2004

Efetuei alguns teste básicos e parece que vai solucionar o meu problema...

Confirmarei mais tarde a solução apresentada se vai ser possivel colocar em produção...

Agradeço sua ajuda...


GOSTEI 0
Bolus

Bolus

01/09/2004

Caro colega,
efetuei alguns testes mais profundos...
Realmente para Criar os comandos
    Create Generators XXXX;
    e
    Set Generator XXXX to 0;
  


Funcionou perfeito, porém para a recuperação do generator não funcionou ...
As linhas de código que utilizei foram:
      sGEN = ´Gen_ID(GEN_CLIFILIAL´||new.Empresa||´_´|| New.Filial || ´,1)´;
    execute statement sGEN into :iGEN;
 


também tentei do seguinte modo:
      sGEN = ´Gen_ID(GEN_CLIFILIAL´||new.Empresa||´_´|| New.Filial || ´,1) into :iGEN´;
    execute statement sGEN;
  

e
    sGEN = ´iGEN = Gen_ID(GEN_CLIFILIAL´||new.Empresa||´_´|| New.Filial || ´,1)´;
    execute statement sGEN;
  


a REsposta que recebi foram:

SQL Code Error: -104
GEN_ID


GOSTEI 0
Beppe

Beppe

01/09/2004

Em vez de chamar gen_id diretamente, use um select:

execute statement ´select gen_id(GEN_CLIFILIAL´ || new.Empresa || ´_´ || new.Filial || ´, 1) from rdb$database´ into :ID;


Declare ID como [b:a502a175c1]bigint[/b:a502a175c1].


GOSTEI 0
Bolus

Bolus

01/09/2004

Beppe,
Obrigado por sua resposta, porem gostaria que o trabalho de controle fosse controlado pelas rotinas Internas do Firebird, por isso estou utilizando o Generators.
Por que inicialmente tinha pensado em criar uma tabela que conteria os contadores, assim todos os contadores seriam controlados por minha aplicação, ou melhor por selects, insert e update. Caso não tenha outra solução, voltarei a essa opção inicialmente gerada.
É que existe a possibilidade de ter muitas conexões simultaneas e seria bom que o controle fosse efetuado pelo Gerenciador do Banco de Dados.

Mesmo assim agradeço a ajuda de todos....


GOSTEI 0
Beppe

Beppe

01/09/2004

Mas vc continua usado generators no código que eu postei. Você só altera um comando, em vez de usar gen_id como função solita, você a usa dentro de um select. É gen_id que recuperará e atualizará o valor do generator.

Percebe?


GOSTEI 0
Bolus

Bolus

01/09/2004

Observei sua resposta e apliquei na Trigger da seguinte maneira:
AS
  declare variable iGen Int;
begin
  /* Trigger text */
  if (New.Filial is null) then
  begin
    execute statement ´select Cast(gen_id(GEN_FILEMP_´||New.Empresa ||´,1) as Integer) from rdb$database´ INTO :iGEN;
    new.Filial=iGEN;
  end
end

Porem esta dando a seguinte mensagem de erro
Invalid Token. Dynamic SQL Error SQL Code Error: -104 Token unknown - line 1, char 35. 0.


Qual seria o caminho neste ponto, estou começando a ficar irritado com o código...

Qualquer ajuda cairia bem, novamente...


GOSTEI 0
Beppe

Beppe

01/09/2004

Tem um erro sintático na criação da sua trigger. A sintaxe dela deveria ser algo assim:
CREATE TRIGGER NOME_DA_TRIGGER FOR SUA_TABELA
ACTIVE BEFORE INSERT POSITION 0
AS
  declare variable iGen Int;
begin
  /* Trigger text */ 
  if (New.Filial is null) then 
  begin 
    execute statement ´select Cast(gen_id(GEN_FILEMP_´||New.Empresa ||´,1) as Integer) from rdb$database´ INTO :iGEN; 
    new.Filial=iGEN; 
  end
end



GOSTEI 0
Bolus

Bolus

01/09/2004

Beppe,
Somente lhe enviei o corpo da Trigger...
Pois ela não gerou erro ao ser criada, mas sim quando esta sendo acionada pelo Banco....
Ou seja quando estou incluindo um registro no meu arquivo os dados coletados é o erro ocorre...

Alguma sugestão...


GOSTEI 0
Beppe

Beppe

01/09/2004

bolus, o erro acusado ´Invalid Token...0´, sugere um erro sintático. Como você disse agora que é na execução, o erro deve estar no execute statement, mas não vi o tal 0 que está causando o erro. Veja no sql monitor se a sentença está bem formada.


GOSTEI 0
Afarias

Afarias

01/09/2004

bom pessoal... no ´final das contas´ temos::

1- ter 1 generator para cada filial nào é uma soluçào ´legal´ (Relacional)
2- EXECUTE STATEMENT é algo q deve ser usado ´em último caso´


qual a ´idéia´ de se ter códigos repetidos para os clientes de filiais diferentes?? isso não é bom em qualquer aspécto.

vc deveria (na minha opnião) ter simplesmente apenas 1 generator criando códigos para TODOS os clientes seja de que filial for e apenas um campo chamado FILIAL para informar a qual filial pertence.


T+


GOSTEI 0
Vinicius2k

Vinicius2k

01/09/2004

Colegas,

Dentro do que o afarias colocou, me permitem sugerir uma coisa ?
1. Manter apenas um generator para cada empresa.
2. Se vc quiser que a ID seja realmente diferente (nestes casos eu prefiro usar uma chave primária concatenada = IDEmpresa e IDCliente), vc pode incrementar o generator baseado num critério, por exemplo, é possível que vc tenha no seu banco 10 milhoes de clientes? se vc achar que é impossível vc poderia dar o valor ao campo ID com um código parecido com este :
New.ID =  (IDEmpresa * 10000000) + GEN_ID(Nome_do_Generator, 1);


o resultado seria :
Empresa  IDCliente
-------------------
001      0010000001
001      0010000002
001      0010000003
002      0020000004
002      0020000005
003      0030000006
...      ...
214      2149999999


Neste caso vc poderia ter até 214 empresas (para não ter problemas com o tipo integer)... e 9.999.999 clientes (contagem geral de todas elas)...

É apenas uma sugestão...

T+


GOSTEI 0
Bolus

Bolus

01/09/2004

Caros colegas,
A ideia é criar um sistema MultiEmpresa que conterá diversas Empresas, com uma quantidade variavel de Filiais e consequentemente diversos clientes....
Como o sistema poderá ser acionado por filiais diversas e empresas diferentes, foi planejada esta solução, pois não ocorrerá duplicação do codigo gerado.
O sistema será utilizado, inicialmente, individualmente nas Filiais, por isso não poderei ter um contador unico para a empresa. Depois será colocado em uma central de controle, que deverá continuar com os contadores já inicializados...
Esta solução beneficia um grande numero de clientes, afinal o código gerado vai ser baseado em Codigo da empresa, código da filial e codigo do cliente na filial, ficando com uma numeração semelhante a demonstrada abaixo:
XXX YYY CCCCCC
onde XXX - Codigo da Empresa (até 999)
YYY - Código da Filial na Empresa (até 999 filiais)
CCCCCC - Código do Cliente na Filial ( até 999999)....

Isso abre uma infinidade de códigos, até o suficiente para cadastrar todos os habitantes da terra.

Espero ter dado uma visão, do por que pretendo utilizar um Generator para a empresa, um generator para filial por empresa e um generator para cliente por filial da empresa.....

Ok....

Espero ter esclarecido o motivo dos generators
Qualquer dúvida entrem em contato.


GOSTEI 0
Bolus

Bolus

01/09/2004

Caros colegas,
Desculpe a informação erronea.....
Após teste na Trigger (Before Insert) informada anteriormente, identifiquei que a mesma esta correta..... O que estava ocasionando erro é a Trigger (After Insert), que coloco Abaixo:
AS
  declare variable sGEN varchar(256);
begin
  /* Trigger text */
  sGEN = ´Create Generator GEN_CLIFILIAL´||new.Empresa||´_´|| New.Filial;
  Execute statement SGEN;
  sGEN = ´Set Generator GEN_CLIFILIAL´||new.Empresa||´_´|| New.Filial|| ´to 0´;
  Execute statement SGEN;
end


Não esquecendo que somente coloquei o corpo da Trigger, que por sinal desativei momentaneamente até solucionar o meu erro...
Pois considero que tenha escrevito algum erro na trigger...

Peço a ajuda dos colega...

Novamente peço desculpa pela informação sobre a trigger errada...


GOSTEI 0
Bolus

Bolus

01/09/2004

Caros colegas,
Encontrei o erro que esta ANTA fez....
na linha
  sGEN = ´Set Generator GEN_CLIFILIAL´||new.Empresa||´_´|| New.Filial|| ´to 0´;
  


deveria ser colocado assim:
 sGEN = ´Set Generator GEN_CLIFILIAL´||new.Empresa||´_´|| New.Filial|| ´ to 0´;
 


Estava faltando um espaço ( ASCII(32)) antes da palavra TO...

Agradeço a ajuda de todos os colegas.....


GOSTEI 0
POSTAR