[firebase-br] Aos interessados: Omelhor Autoincrementosequencial

Caio Oliveira news em caiosistemas.com.br
Qui Abr 6 12:22:58 -03 2006


Vou expor uma outra técnica semelhante ao uso da função MAX; nunca tive 
problemas com numeração de documentas e possuo instalações com mais de 
160 usuários concorrentes. Não é a solução mais rápida; mas não falha nunca.

Uma Procedure que lê o último código utilizado (no meu caso a base foi 
convertida de um sistema antigo feito em Clipper e usava campos caracter 
para o código; mantivemos após conversão; portanto se vc usa campos 
INTEGER basta esquecer os processos de conversão utilizados abaixo).

/*
    PEDIDOS DE VENDA / NOTAS FISCAIS
    GETULTIMOPEDIDONOTA
    Devolve o numero do ultimo PEDIDO DE VENDA ou NOTA FISCAL em CEPNT001
  */
^
CREATE PROCEDURE "GETULTIMOPEDIDONOTA"
(
  "IDEMP" INTEGER,
  "SERIE" CHAR(3)
)
RETURNS
(
   "NUMERO" INTEGER
)
AS
DECLARE VARIABLE "ROWS" INTEGER;
Begin
ROWS = 0;
FOR select CAST(NF_NOTA AS INTEGER)+1 from CEPNT001
where id_emp = :idemp AND NF_SERIE = :serie order by NF_NOTA DESC
     into :NUMERO
DO
  SUSPEND;
  Begin
     if (NUMERO is null) then NUMERO = 1;
     rows = rows + 1;
     if (rows = 1) then EXIT;
  End
END
^

Uma TRIGGER que é aciona a procedure e incrementa o campo código; alêm 
do ID do registro e data
/*
TG_PEDIDOSNOTAS
-------------------------
Essa TRIGGER insere o numero do próximo doc. Documento (NOTA FISCAL)
ou PEDIDO DE VENDA na tabela CEPNT001 e ainda o ID  do documento e data.
Autor: Caio José Hugueney Lopes de Oliveira
*/
^
CREATE TRIGGER TG_PEDIDOSNOTAS FOR CEPNT001
    ACTIVE BEFORE INSERT
    POSITION 0
    AS
    DECLARE VARIABLE PROXNUM INTEGER;
    DECLARE VARIABLE PROXCOD VARCHAR(6);
    BEGIN
      EXECUTE PROCEDURE GETULTIMOPEDIDONOTA( NEW.ID_EMP, NEW.NF_SERIE )
      RETURNING_VALUES PROXNUM;

      IF (PROXNUM IS NULL) THEN PROXNUM = 1;

      EXECUTE PROCEDURE PC_STRZERO PROXNUM, 6
      RETURNING_VALUES PROXCOD;

      IF (NEW.ID_CEPNT001 IS NULL) THEN
      NEW.ID_CEPNT001 = GEN_ID( GEN_CEPNT001, 1);
      NEW.DATAHORA = CURRENT_TIMESTAMP;

      IF (NEW.NF_DATA IS NULL) then NEW.NF_DATA = CURRENT_DATE;

      IF ((NEW.NF_NOTA IS NULL) OR (NEW.NF_NOTA='')) then
      NEW.NF_NOTA = PROXCOD;

    END;
   ^

Essa procedure PC_STRZERO é chamada apenas para converter e CHAR e 
incrementar com zeros à esquerda o número obtido; quem se interessar 
segue o código abaixo:

/* PC_StrZero(str)
// Essa procedure devolve o tamanho da STRING passada como parâmetro.
// Original de: Ivan Prenosil
Adaptada por Caio Jose Hugueney Lopes de Oliveira */
CREATE PROCEDURE PC_StrZero (vstr VARCHAR(100), nTam INT)
RETURNS (vstr2 varchar(100)) AS
DECLARE VARIABLE vallen INT;
BEGIN
vstr2 = null;
EXECUTE PROCEDURE PC_LEN vstr
RETURNING_VALUES vallen;

IF (vstr IS NULL) THEN EXIT;
IF (nTam IS NULL) THEN EXIT;
vstr2 = vstr;
WHILE (nTam > vallen) DO
    BEGIN
    vstr2 = '0'||vstr2;
    vallen = vallen +1;
    END

END
^

/* PC_len(str)
// Essa procedure devolve o tamanho da STRING passada como parâmetro.
// Original de Ivan Prenosil
  Adaptada por: Caio José Hugueney Lopes de Oliveira */
CREATE PROCEDURE PC_Len (str VARCHAR(100))
RETURNS (len INTEGER) AS
DECLARE VARIABLE pat VARCHAR(100);
BEGIN
len = null;
IF (str IS NULL) THEN EXIT;
pat = '';
len = 0;
WHILE (NOT str LIKE pat) DO BEGIN
pat = pat || '_';
len = len + 1;
END
END
^

Abraço à todos!

Caio

Eduardo Jedliczka (TeamFB) escreveu:
> Bom, deixa eu por lenha da fogueira...
> 
> NÃO EXISTE SOLUÇÃO MÁGICA PARA NÚMEROS ININTERRUPTOS SEQUENCIAIS EM BANCO DE 
> DADOS RELACIONAIS.
> 
> Se você precisa se preocupar em "Sequencias Reais" em Notas Fiscais, 
> Cheques, e outros documentos deste porte, não adianda usar um 
> Sequence/Generator (nem no Oracle!!!), e tem que se ter muito sangue frio 
> para se utilizar "Select Max" em aplicações com mais que meia-dúzia de 
> operadores simultâneos.
> 
> Há paliativos "universais" para se resolver isto, entre eles uma "tabela de 
> gabarito" contendo (dependendo do caso) os "furos" e códigos ainda não 
> utilizados na emissão de documentos. Só vale lembrar, que para isto 
> funcionar, é necessário que esta tabela esteja numa transação "diferente" 
> (auto-commit, read-commited, with lock), onde só será consultada e alterada, 
> após o Commit da transação principal.
> 
> Também há soluções "exclusivas" do InterBase/FireBird... pode-se utilizar 
> "eventos" para capturar qual foi o último número de nota/cheque emitido e 
> assim criar uma sequencia sem falhas.
> 
> (Cantu que tal acrescentar este assunto na temática das palestras do 3º FDD 
> ???)
> 
>  ======================
> Eduardo Jedliczka
> Membro do TeamFB - FireBase
> Apucarana - PR
> ======================
> 
> ----- Original Message ----- 
> From: "Andrei Luís" <compuvale.software em gmail.com>
> To: "FireBase" <lista em firebase.com.br>
> Sent: Thursday, April 06, 2006 9:17 AM
> Subject: Re: [firebase-br] Aos interessados: Omelhor 
> Autoincrementosequencial
> 
> 
> Uma solução que se usava bastante na época do Clipper, era de uma tabela a
> parte para guardar a sequência. Ex.:
> 
> Tabela     Campo   Sequencia
> Clientes    ID            1
> Produtos  ID            4
> Pedidos   ID             10
> ...
> 
> Acho que saiu na Clube Delphi ou na SQL Magazine uns meses atras uma solução
> parecida com essa, o título era algo como: "Campos auto-incremento para
> qualquer BD". O colunista usou Firebird para mostrar os exemplos.
> 
> []
> Andrei
> 
> 
> Em 06/04/06, Luis Asensio - Control/P Sistemas <luis em controlp.com.br>
> escreveu:
>> Boa dia a todos!!!
>>
>>        Essa semana fiz um teste comparando a eficiencia do auto-incremento
>> das duas formas descritas. Uma realizando um MAX na tabela e outra usando
>> a
>> Generator. O teste foi bem simples: Rodei uma aplicatico no qual me inflou
>> uma determinada tabela em 100.000 e inserir um cronometro interno para
>> poder
>> comparar o tempo. O resultado foi uma diferença de 3:00 min, a mais para o
>> Trigger com o MAX. O Generator com muitos registros é mais rápido acima de
>> 20.000 registros. Concordo que para um sequencial integro o MAX minimiza o
>> problema.
>>
>>
>> Abraços
>>
>>
>> Luis Asensio
>> Control/P Sistemas
>> Setor de Desenvolvimento
>> luis em controlp.com.br
>> http://www.controlp.com.br
>>
>> -----Original Message-----
>> From: lista-bounces em firebase.com.br [mailto:lista-bounces em firebase.com.br]
>> On Behalf Of Listas - VirtualComp
>> Sent: quarta-feira, 5 de abril de 2006 18:12
>> To: Carlos H. Cantu; FireBase
>> Subject: Re: [firebase-br] Aos interessados: Omelhor
>> Autoincrementosequencial
>>
>> CREATE TRIGGER GER_COD_CLIENTES FOR CLIENTES ACTIVE BEFORE INSERT POSITION
>> 0
>> AS declare variable cod integer; begin  select max(codigo_cli)  from
>> clientes  where clientes.empresa_cli = new.empresa_cli  into :cod;  if
>> (cod
>> is null) then
>>     cod = 0;
>> new.codigo_cli = cod + 1;
>> end
>>
>>
>> com essa trigger eu tenho 3..4 empresas cadastradas cada empresa tem uma
>> sequencia clientes e nunca da problema...
>>
>>
> ______________________________________________
> FireBase-BR (www.firebase.com.br) - Hospedado em www.bavs.com.br
> Para editar sua configuração na lista, use o endereço 
> http://mail.firebase.com.br/mailman/listinfo/lista_firebase.com.br
> Para consultar mensagens antigas: http://firebase.com.br/pesquisa 
> 
> 
> ______________________________________________
> FireBase-BR (www.firebase.com.br) - Hospedado em www.bavs.com.br
> Para editar sua configuração na lista, use o endereço http://mail.firebase.com.br/mailman/listinfo/lista_firebase.com.br
> Para consultar mensagens antigas: http://firebase.com.br/pesquisa
> 





Mais detalhes sobre a lista de discussão lista