Ir para conteúdo
Fórum Script Brasil
  • 0

filtro automatico em um DBComboBox. Como?


Greed

Pergunta

Bom dia galera,

eu gostaria de saber como eu faço para o DBComboBox ir filtrando o banco de dados conforme o usuário digita.

Assim:

Ele vai procurar pelo cliente Alan, quando ele digita A, todos os clientes com A irão aparece, quando ele digita L, todos os clientes com AL irão aparecer.

Estou pensando nisso, pois imagine um banco com 300 clientes, como vai ficar a lista para ele selecionar? Imensa correto?

No DBComboBox se você clicar e for digitando as palavras ele vai aparecendo, mas a lista continua enorme e eu queria reduzir o tamanho da lista para as palavras filtradas.

Alguém sabe como fazer isso?

Grato

Link para o comentário
Compartilhar em outros sites

11 respostass a esta questão

Posts Recomendados

  • 0

procedure Tform1.edit1Change(Sender: TObject);
begin
   if edit1.Text <> '' then
   begin
      with qquery do
      begin
         SQL.Clear;
         SQL.Text := 'Select * from Cliente ' +
                           'where nome like"'+edit1.Text+'%" ' +
                           'order by nome limit 50';
         Active := true;
      end;
   end;
end;

Não esqueça de criar um índice pelo nome para que a pesquisa não seja em TABLE SCAN e degenere exponencialmente conforme o crescimento da tabela.

Não faça pesquisa like de outra forma que a apresentada acima ou será TABLE SCAN.

Link para o comentário
Compartilhar em outros sites

  • 0

Greed, supondo que esta consulta também será em tabela Paradox (mencionada em seu outro post), caso ocorra erro na execução da mesma (ao abrí-la), retire o " limit 50" da cláusula Order By, pois o Paradox não dá suporte a esta funcionalidade (se não me falha a memória).

Abraços

Link para o comentário
Compartilhar em outros sites

  • 0

Olá Denis

Li sua resposta e gostaria de saber se pode me explicar o que é e como funciona o TABLE SCAN pois eu uso a consulta como abaixo e ai surgiu a curiosidade de saber o que é isso e se minhas consultas podem melhorar ou estão da forma correta...

TABELA.Close;
       TABELA.SQL.Clear;
       TABELA.SQL.Add('SELECT * From TABELA);
       TABELA.SQL.Add('Where CAMPOLike :pCli ');
       TABELA.SQL.Add('Order By Codigo');
       TABELA.Parameters[0].Value := Edit1.Text + '%';
       TABELA.Open;

Abraços

Link para o comentário
Compartilhar em outros sites

  • 0

ixi, não funcionou não :mellow:

Eu não achei o evento OnChange no DBLookupComboBox. eu inseri no evento OnKeyPress, mas não funcionou o código!

Desculpa a demora em responder.

Vivendo&Aprendendo, eu não entendi o seu código.

Valeu Micheus, eu retirei o código, mas mesmo assim ele não filtra só os campos com as letras correspondentes.

Link para o comentário
Compartilhar em outros sites

  • 0

Olá Greed!

Na verdade você perguntou sobre o DbCombobox, mas está bem.

Deixa eu te dar uma dica, não sei na verdade o porque do seu interesse em fazer usando o Combo, mas ai vai uma dica:

Eu utilizo um ComboBox para selecionar em qual campo da tabela eu quero fazer a busca e um edit para buscar determinado registro nesta tabela e neste campo selecionado no Combo. Ai sim uso esse código que te passei que conforme eu vou digitando no Edit ele vai eliminando os registros que não coincidem com o que está sendo digitado.

Outra opção é utilizar um edit e no evento onchange este código que auto completa o edit com os dados da tabela:

procedure TFrmSaidas.EdtNomeChange(Sender: TObject);
Var Aux : Integer;
begin
  TABELA.Close;
  TABELA.Open;
  if TABELA.Locate('Nome',copy(Edit1.Text,1,Edit1.SelStart),[loCaseInsensitive,loPartialKey]) then
  begin
    Edit1.OnChange := nil; // Não ativar o evento agora.
    Aux := Edit1.SelStart; // Posição do cursor no EditFornecedor
    Edit1.Text := TABELA.FieldByName('Nome').AsString; // Foi o que encontramos pois o codigo só passa por aqui se existe a informação
    Edit1.SelStart := Aux; // Atualizamos a posição do cursor.
    Edit1.OnChange := Edit1Change; // Agora podemos chamar novamente.
  end;
end;

Qualquer coisa posta ai...

Abraços

Editado por Vivendo&Aprendendo
Link para o comentário
Compartilhar em outros sites

  • 0
Olá Denis

Li sua resposta e gostaria de saber se pode me explicar o que é e como funciona o TABLE SCAN (...)

Vivendo&Aprendendo, em suma, TABLE SCAN é a condição em que o banco de dados terá que varrer todos os registros de sua tabela em busca daqueles que satisfazem a condição desejada.

Quando existe algum índice que possa ser aproveitado pelo banco de dados, as consultas são feitas sobre ele para retornar o registros sem que seja necessário varrer toda a tabela.

Por exemplo, buscar todos os nomes que começam com a letra "M", em uma tabela (Nomes) onde fisicamente a sequência de inclusão foi a seguinte:

Pedro

Ubirajara

Leandro

Moacir

Maria

Cecília

Antônio

Juvenal

Marcia

select nome from Nomes where nome like "M%"
não existindo um índice para o campo nome, o banco tem que ler todos os registros (09) para lhe retornar apenas os 03 compatíveis com a busca. Havendo um índice, o mesmo estará organizado de modo a fornecer acesso aos nomes na sequência: Antônio Cecília Juvenal Leandro Marcia Maria Moacir Pedro Ubirajara Assim, a busta será primeiramente realizada no índice de modo buscar apenas os 03 registros na tabela Nomes. Mas, no caso específico do uso de like, esta otimização é feita apenas quando você não usa um "%" antes do substring sendo procurada. Ex. %M% ou %M. Com isto, torna-se conveniente uma boa avaliação das consultas realizadas em campos que não possuem índice e conforme relevância, é conveniente criar índices que acelerem estas consultas. Quanto mais registros existirem na tabela, maior será a perda de performance por conta do TABLE SCAN. Observe, entretanto, que isto é válido para os bancos de dados "de verdade". Para as tabelinhas Paradox (*.db), DBase ou Clipper (*.dbf) eu não estou certo de que os drivers façam uso de tal recurso na instrução LIKE. _____________________________
Eu não achei o evento OnChange no DBLookupComboBox. eu inseri no evento OnKeyPress, mas não funcionou o código!
Greed, este componente tem seu próprio esquema de localização pela digitação. Observe que se você for digitando o nome sem fazer intervalo (+/- 1 caracter por segundo), você notará que ele irá posicionando a seleção na lista de acordo com o que foi digitado. Este componente, diferente do TDBComboBox, não tem a caixa de edição - ele monitora o evento keypressed. Voce está utilizando ele para filtra dados apenas? Não configurou as propriedades DataSource e DataField, então? Se sim, neste caso, não coloque um "*" na cláusula SELECT, mas apenas o campo de referência do cliente (codigo) e o nome do cliente. Daí, apenas ao sair do componente (OnExit) você buscaria todos os dados do cliente (uma única vez). Segue uma sugestão de implementação para atender a solicitação inicial: - você precisará declarar uma variável do tipo string na sessão private do seu form (LkpString); - como estou quase certo de que você está usando Paradox (você não confirmou isto no meu outro post), ajuste sua consulta para algo como:
select cod_cli, nom_cli 
from cliente where UPPER(nom_cli) like UPPER(:nom_cli) 
order by nom_cli
observe o detalhe da função UPPER. Isto forçará a comparação sempre com maiúsculas e garante a localização (coisa das limitações do Paradox); - adapte o código abaixo de acordo com o nome de seus componentes.
procedure TForm1.FormShow(Sender: TObject);
begin
 // mostra todos as linhas ao apresentar o form
  QryClientesLkp.ParamByName('customer').AsString := '%';
  QryClientesLkp.Open;
end;

procedure TForm1.DBLookupComboBox1Enter(Sender: TObject);
begin
 // inicializa a substring quando componente recebe o foco
  LkpString := '';
end;

procedure TForm1.DBLookupComboBox1KeyPress(Sender: TObject; var Key: Char);
begin
  case Key of
    #27 :  // Escape, limpa substring mostrando tudo
       LkpString := '';
    #08 :  // BackSpace, apaga último caracter da substring
       Delete(LkpString, Length(LkpString), 1);
    #32..#255 :  // caracteres aceitos - exclui os especiais, abaixo de 32
      // este teste "ignora" caracteres após uma
      // substring não ser encontrada
       if QryClientesLkp.RecordCount > 0 then
         LkpString := LkpString +Key;
  end;
  if Key in [#27, #08, #32..#255] then
  begin
    QryClientesLkp.Close;
    QryClientesLkp.ParamByName('nom_cli').AsString := LkpString +'%';
    QryClientesLkp.Open;
  end;
end;

nesta aplicação, não é necessário "limpar" o parâmetro Key quando nós o processamos.

Abraços

Link para o comentário
Compartilhar em outros sites

  • 0

Oi,'Micheus'!

Muito boa a expicação. Só para complementar o que você estava dizendo ao colega 'Vivendo&Aprendendo', o uso de funções, tais como a que você exemplificou abaixo, também geram TABLE SCAN, pois o motor do banco de dados será obrigado a avaliar cada um dos registros tranformando o conteúdo do atributo em maiúscula para poder compará-lo com o outro lado da igualdade.

select cod_cli, nom_cli 
from cliente where UPPER(nom_cli) like UPPER(:nom_cli) 
order by nom_cli

Para uma melhor estruturação (performance) do banco de dados o ideal é que atributos do tipo string (char, varchar, text, etc.) estjam guardados em um único formato. Ou tudo em maiúsciulas ou tudo em minúsculas.

Link para o comentário
Compartilhar em outros sites

  • 0
... o uso de funções, tais como a que você exemplificou abaixo, também geram TABLE SCAN, pois o motor do banco de dados será obrigado a avaliar cada um dos registros tranformando o conteúdo do atributo em maiúscula para poder compará-lo com o outro lado da igualdade.

...

Para uma melhor estruturação (performance) do banco de dados o ideal é que atributos do tipo string (char, varchar, text, etc.) estjam guardados em um único formato. Ou tudo em maiúsciulas ou tudo em minúsculas.

Bem lembrada a questão do uso das funções Denis. Se ele estiver usando mesmo o Paradox, ou ele aplica sua sugestão com relação a forma como guarda as strings ou vai ter que usar a função mesmo.

Há ainda de se considerar que, algumas vezes, também pode ser relevante observar a questão da acentuação nestas buscas. É bom buscar informações sobre como o banco que você usa se comporta em relação a estes tópicos para que não deixe seu usuário sem a informação correta.

Abraços

Link para o comentário
Compartilhar em outros sites

  • 0

Apenas acrescentando a título de informação...

No caso do Firebird é possível criar um índice com uma expressão. Neste exemplo, teríamos um índice criado com a expressão UPPER(nom_cli):

CREATE INDEX IDX_NOME_UPPER ON CLIENTE COMPUTED BY (UPPER(nom_cli));
depois na consulta, usando o UPPER e passando o parâmetro já em maiúsculo (p.e. usando a função UpperCase), o banco faz uso do índice acima (IDX_NOME_UPPER):
select cod_cli, nom_cli
from cliente where UPPER(nom_cli) like :nom_cli
order by nom_cli

acredito que outros bancos permitam algo semelhante.

Abraços

Editado por Micheus
Corrigido nome do campo no create index - de nome para nom_cli
Link para o comentário
Compartilhar em outros sites

  • 0

Oi, 'Micheus' !

...No caso do Firebird é possível criar um índice com uma expressão ... acredito que outros bancos permitam algo semelhante.
Infelizmente está não é uma verdade para o MySQL.

Link para o comentário
Compartilhar em outros sites

Participe da discussão

Você pode postar agora e se registrar depois. Se você já tem uma conta, acesse agora para postar com sua conta.

Visitante
Responder esta pergunta...

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emoticons são permitidos.

×   Seu link foi incorporado automaticamente.   Exibir como um link em vez disso

×   Seu conteúdo anterior foi restaurado.   Limpar Editor

×   Você não pode colar imagens diretamente. Carregar ou inserir imagens do URL.



  • Estatísticas dos Fóruns

    • Tópicos
      152,2k
    • Posts
      651,9k
×
×
  • Criar Novo...