[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