[firebase-br] Codigo vago

Escovador de Bits escovadordebits em gmail.com
Sex Fev 13 18:57:31 -03 2009


Bom dia/tarde Augusto.

Grande Augusto, fiz alguns testes para encontrar o meio mais simples e 
rápido de resolver esse seu problema.

A solução que funcionou aqui funciona através de uma stored procedure 
que retorna o número a ser utilizado para "tapar o buraco".

Nos meus testes, eu criei a seguinte tabela:

CREATE TABLE NUMEROS (CAMPO CHAR(6) NOT NULL);

E inclui alguns registros de teste.

Criei a seguinte stored procedure:

SET TERM ^ ;

CREATE OR ALTER PROCEDURE PROXIMO_NUMERO_VAGO
RETURNS (NUMERO_VAGO INTEGER) AS
DECLARE VARIABLE INICIO INTEGER;
DECLARE VARIABLE MEIO INTEGER;
DECLARE VARIABLE FIM INTEGER;
BEGIN
  -- Obtem o maior valor utilizado e a quantidade de registros.
  SELECT CAST(MAX(CAMPO)AS INTEGER),COUNT(*) FROM NUMEROS INTO 
:NUMERO_VAGO, :FIM;
  -- Sem registros? Ou nao ha "buraco" algum?
  IF ((FIM = 0) OR (NUMERO_VAGO = FIM)) THEN
    -- Retorna o proximo valor da sequencia.
    NUMERO_VAGO = FIM + 1;
  ELSE
  BEGIN
    -- Inicializa a busca binaria.
    INICIO = 1;
    -- Laco da busca binaria.
    WHILE (INICIO <= FIM) DO
    BEGIN
      -- Calcula o indice do registro a ser acessado.
      MEIO = (INICIO + FIM) / 2;
      -- Obtem o valor contido nesse registro.
      SELECT FIRST 1 SKIP (:MEIO - 1) CAST(CAMPO AS INTEGER) FROM 
NUMEROS ORDER BY CAMPO INTO :NUMERO_VAGO;
      -- O "buraco" esta apos o registro atual?
      IF (NUMERO_VAGO = MEIO) THEN
        -- Continua a busca na segunda metade do intervalo atual.
        INICIO = MEIO + 1;
      ELSE
        -- Continua a busca na primeira metade do intervalo atual.
        FIM = MEIO - 1;
    END -- WHILE
    -- O "buraco" esta entre o registro anterior e o atual?
    IF (NUMERO_VAGO > MEIO) THEN
      -- Informa o numero a ser utilizado para "tapar o buraco".
      NUMERO_VAGO = MEIO;
    ELSE
      -- Informa o numero a ser utilizado para "tapar o buraco".
      NUMERO_VAGO = MEIO + 1;
  END -- ELSE
  -- Retorna o valor calculado.
  SUSPEND;
END^

SET TERM ; ^

GRANT SELECT ON NUMEROS TO PROCEDURE PROXIMO_NUMERO_VAGO;

Agora, experimente alterar os registros da tabela NUMEROS e obter o 
resultado dessa stored procedure como no seguinte exemplo:

SELECT NUMERO_VAGO FROM PROXIMO_NUMERO_VAGO

Resumindo a lógica que utilizei nessa stored procedure, fiz a pesquisa 
utilizando uma busca binaria, que só funciona se o conjunto de valores 
estiver ordenado, daí o ORDER BY CAMPO.

Como estou utilizando um FIRST 1 SKIP (MEIO - 1), só estou acessando um 
registro específico de cada vez.

Utilizando essa técnica, não necessitamos executar uma busca sequencial, 
e a quantidade máxima de leituras e comparações pode ser calculada pelo 
logaritmo da quantidade total de registros (COUNT(*)) na base 2, ou seja:

Se a tabela tiver até 8 registros, fará no máximo, 3 acessos, pois 2 
elevado a 3 resulta 8.
Se a tabela tiver até 16 registros, fará no máximo, 4 acessos, pois 2 
elevado a 4 resulta 16.
Se a tabela tiver até 32 registros, fará no máximo, 5 acessos, pois 2 
elevado a 5 resulta 32.
Se a tabela tiver até 64 registros, fará no máximo, 6 acessos, pois 2 
elevado a 6 resulta 64.
...
Se a tabela tiver até 1.024 (1Kb) registros, fará no máximo, 10 acessos, 
pois 2 elevado a 10 resulta 1.024.
...
Se a tabela tiver até 1.048.576 (1Mb) registros, fará no máximo, 20 
acessos, pois 2 elevado a 20 resulta 1.048.576.
...
Se a tabela tiver até 1.073.741.824 (1Gb) registros, fará no máximo, 30 
acessos, pois 2 elevado a 30 resulta 1.073.741.824.

E assim por diante...

Assumindo que existe um índice para o campo em questão (chaves primárias 
já criam um índice associado), o acesso realmente é bastante rápido, e 
além disso, o ORDER BY CAMPO não perde tempo reordenando o que já está 
ordenado pelo próprio índice.

Agora é só você adaptar esses exemplos ao seu problema e verificar se 
seria uma solução viável.

Espero ter ajudado mais que atrapalhado.

Augusto junior escreveu:
> Tenho um cadastro onde existe um campo char(6) ... esse campo guarda um
> valor numerico com zeros a esquerda..
>
> 000001
> 000002
> 000003
> 000004.....
>
> acontece que esse campo o cliente que define o valor do mesmo.... e colocado
> manualmente... e sempre sendo um valor unico...
>
> agora ele me pediu para ter uma opcao de o sistema informar um numero vago
> ....
>
> fiz isso usando um contador numerico  que vai incrementando em um looping
> ... e a cada incremento faco a busca usando locate para
> ver se ja existe ou nao ..
>
> funcionou perfeitamente ... mas a lentidao do locate desanima...
>
> existe alguma forma de fazer um sql que retorne o primeiro valor vago ?
>
> Grato
> Augusto
> ______________________________________________
> FireBase-BR (www.firebase.com.br) - Hospedado em www.locador.com.br
> Para saber como gerenciar/excluir seu cadastro na lista, use: http://www.firebase.com.br/fb/artigo.php?id=1107
> Para consultar mensagens antigas: http://firebase.com.br/pesquisa
>
>   




Mais detalhes sobre a lista de discussão lista