GARANTIR DESCONTO

Fórum Consulta aproximada (tipo google, forum, etc...) #337512

07/02/2007

0

caros colegas, tenho uma tabela no Firebird povoada de registros...
componentes de acesso usados: dbx

precisaria fazer uma consulta em um determinado campo da tabela que:

1. não diferencie letras maiusculas de minusculas
2. vamos supor que eu queira realizar uma consulta no campo ´sinopse´ da tabela ´livros´, e vamos supor tambem que um dos registros desse campo seja: [b:decd4dc69f]´entao joao subiu no pé de feijao e sumiu´[/b:decd4dc69f]

Gostaria que tanto se eu digitasse no edit da consulta: ´joao subiu´ como eu digitasse: ´subiu joao´, esse registro fosse encontrado, ou seja uma pesquisa tipo a do google, a do forum aqui, etc...

alguem tem alguma dica de por onde posso começar?

Abraços!


Mahdak

Mahdak

Responder

Posts

08/02/2007

Weber

Você pode fazer isto usando like, faça uma rotina para identificar as palavras que o usuário colocou, então separeas e utilize um like para cada palavra.


Responder

Gostei + 0

09/02/2007

Mahdak

Você pode fazer isto usando like, faça uma rotina para identificar as palavras que o usuário colocou, então separeas e utilize um like para cada palavra.


sim, mas se eu fizer isso creio que ainda não vá funcionar... vamos ao exemplo:

1. frase digitada no edit1.text: ´forum clube delphi´

2. palavras identificadas e inseridas uma a uma em uma tabela.cds: ´forum´, ´clube´, ´delphi´

3. vamos supor que o unico registro no banco que contem o que eu queira encontrar está assim: ´no forum clube delphi voce encontra o que busca´, ou seja a frase digitada, esta contida dentro do regitro da tabela, porem misturada...

4. no SqlDataSet: ´select * from tabela where campo like ´+ edit1.text;

5. resultado da consulta := nada

Obs, eu precisaria que essa consulta retornasse aquele unico registro no caso. Refletindo, eu vi que da de fazer isso pegando registro a registro da tabela e fazendo a separação das palavras desse registro em uma tabela .cds e comparando com as palavras do edit, porem minha tabela é extensa e cada campo é um varchar(1000)...

alguma uma outra solução para isso???

um forte abraço!


Responder

Gostei + 0

09/02/2007

Emerson Nascimento

sim, mas se eu fizer isso creio que ainda não vá funcionar... vamos ao exemplo: 2. palavras identificadas e inseridas uma a uma em uma tabela.cds: ´forum´, ´clube´, ´delphi´ [...] 4. no SqlDataSet: ´select * from tabela where campo like ´+ edit1.text;

creio que a dica do Weber funciona:
(pressupondo que você já separou as palavras do edit num array ou num stringlist)

- se vc quiser que tenha TODAS AS PALAVRAS, independente da ordem:
  instrucao := ´select * from tabela where ´;
  for i := 0 to high(arraydepalavras) do
  begin
    if i > 0 then instrucao := instrucao + ´ and ´;
    instrucao := instrucao + ´campo like ´+quotedstr(´¬´+arraydepalavras[i]+´¬´);
  end;

- se vc quiser que tenha QUALQUER UMA DAS PALAVRAS, troque o [b:a809ff264f]and[/b:a809ff264f] por [b:a809ff264f]or[/b:a809ff264f].


Responder

Gostei + 0

09/02/2007

Mahdak

creio que a dica do Weber funciona: (pressupondo que você já separou as palavras do edit num array ou num stringlist)
  instrucao := ´select * from tabela where ´;
  for i := 0 to high(arraydepalavras) do
  begin
    if i > 0 then instrucao := instrucao + ´ and ´;
    instrucao := instrucao + ´campo like ´+quotedstr(´¬´+arraydepalavras[i]+´¬´);
  end;
[/b] por [b:d7370fc152]or[/b:d7370fc152].



O irmão beleza! só a nivel de informação meu sistema é multi-camadas... onde tudo é parametrizado... nao envio sql ao servidor, entao consegui resolver assim:

no SqlDataSet do meu servidor de aplicação eu tenho:
select * from tabela where campo LIKE :Parametro

no aplicativo cliente(onde está o clientDataSet das palavras) eu tenho algo como:
cdsTermos.First;
        Dm.cdsTabela.First;
        while not cdsTermos.Eof do
        begin
            DM.Connection.Open;
            try
              DM.cdsTabela.Close;
              DM.cdsTabela.Params[0].AsString := ´¬´ + cdsTermosTERMO.AsString + ´¬´;
              DM.cdsTabela.Open;
            finally
            DM.Connection.Close;
            end;
            cdsTermos.Next;
        end;


muito obrigado emerson, sua dica foi imprescindivel para eu conseguir solucionar esse pobreeeema...

abração!!!


Responder

Gostei + 0

09/02/2007

Emerson Nascimento

não quero questionar seu método de trabalho, mas não seria mais fácil montar essa instrução e mandá-la completa, ao invés de fazer vários acessos ao servidor, como você está fazendo? acho que da forma que você está fazendo a performance da aplicação fica baixa, por conta desses múltiplos acessos.

eu também trabalho com n-camadas com acesso remoto de vários lugares do país para o servidor em São Paulo e, ao meu ver, um código assim:
  if BuscaTodasAsPalavras then
    Condicao := ´ and ´
  else
    Condicao := ´ or ´;

  instrucao := ´select * from tabela where ´;
  for i := 0 to high(arraydepalavras) do
  begin
    if i > 0 then instrucao := instrucao + Condicao;
    instrucao := instrucao + ´campo like ´+quotedstr(´¬´+arraydepalavras[i]+´¬´);
  end; 

  DM.Connection.Open;
  try
    DM.cdsTabela.Close;
    DM.cdsTabela.CommandText := instrucao;
    DM.cdsTabela.Open;
    [faça o que tem q fazer]
  finally
    DM.Connection.Close;
  end;

seria bem mais rápido, pois a conexão com o banco seria feita apenas 1 vez e os dados trazidos de uma única vez, evitando queda na performance e tráfego de rede desnecessário (seja rede local ou internet).


Responder

Gostei + 0

09/02/2007

Mahdak

sim sua ideia é perfeita!! e concordo plenamente com voce quanto ao trafego menor na rede por ser uma unica requisição, porem como fica o conceito de multi camadas, onde o cliente envia parametros ao servidor de aplicação que por sua vez envia sql ao servidor de banco de dados???

posso estar terrivelmente enganado, mas se eu tiver o minimo de razao nessa lógica, nao teria mais por que eu usar essa arquitetura multi-camadas, poderia apenas usar uma camada simples...

por favor, me corrija se eu estiver enganado brother...

ahh e outra coisa... cade a função Lower do Firebird 1.5.3 ???

dei um [b:527a305dae]´select * from tabela where Lower(campo) LIKE :Parametro´[/b:527a305dae] e olha o erro que me foi retornado:

DataBase Server Error: Function Unknow lower

saberias me dizer o que pode estar acontecendo?

abraços!


Responder

Gostei + 0

09/02/2007

Emerson Nascimento

no conceito 2 camadas, você abre uma conexão ao banco de dados da sua máquina (só aí a performance já fica comprometida, com esse ´link´ pesado aberto constantemente) e executa as instruções diretamente da sua máquina.

mas da forma que eu passei acontecerá o conceito de n-camadas:
você envia a instrução, o provider pega essa instrução, executa no servidor e te devolve o resultado. n-camadas clássico.

quanto à falta da Lower(), não sei te dizer o que houve.


Responder

Gostei + 0

12/02/2007

Mahdak

certo brother, entao vamos lá, vou migrar para a sua sugestão... só to com um probleminha em trocar aquele ´arraydepalavras´ pelos dados contidos em memória em um campo do meu ClientDataSet...

sql := ´select * from NBR10004_2004_RES where ´;
for i := 0 to cdsTermosR.RecordCount do
begin
       if i > 0 then sql := sql + ´ AND ´;
       sql := sql + ´RP like ´+quotedstr(´¬´+cdsTermosRTERMO.Value[i]+´¬´);
end;


fiz uma gambiarra com o seu código como pode-se notar acima... e nao deu certo por que eu to viajando naquela ideia do while ainda...
vamos supor que no campo TERMO do cdsTermosR, houvessem 2 registros, que poderiam ser por exemplo: ´clube´, ´delphi´

o retorno do código acima atualmente é:
select * from NBR10004_2004_RES where RP like ´¬delphi¬´ AND RP like ´¬delphi¬´ AND RP like ´¬delphi¬´


quando deveria ser:
select * from NBR10004_2004_RES where RP like ´¬clube¬´ AND RP like ´¬delphi¬´



pode me ajudar com isso???

um abração


Responder

Gostei + 0

13/02/2007

Mahdak

resolvido... foi só dar last e prior pra mandar o registro se mover....

cdsTermosR.Last;
sql := ´select * from NBR10004_2004_RES where ´;
for i := 1 to cdsTermosR.RecordCount do
begin
if i > 0 then sql := sql + ´ AND ´;
sql := sql + ´RP like ´+quotedstr(´¬´+cdsTermosRTERMO.AsString+´¬´);
cdsTermosR.Prior;
end;


[]´s


Responder

Gostei + 0

13/02/2007

Emerson Nascimento

utilize o [i:0e74e4de03]for[/i:0e74e4de03] para arrays/listas. no seu caso faça:
(para localizar todos os termos. note que a condição [i:0e74e4de03]AND[/i:0e74e4de03] está ´engessada´)
sql := ´select * from NBR10004_2004_RES where ´;

cdsTermosR.First;
while not cdsTermosR.Eof do
begin
  if cdsTermosR.Recno > 1 then sql := sql + ´ AND ´;
  sql := sql + ´RP like ´+quotedstr(´¬´+cdsTermosRTERMO.AsString+´¬´);
  cdsTermosR.Next;
end;


ou você pode permitir a busca por ao menos um dos termos, fazendo assim:
if Checkbox_BuscaTodosOsTermos.Checked then
  Condicao := ´ AND ´
else
  Condicao := ´ OR ´;

sql := ´select * from NBR10004_2004_RES where ´;

cdsTermosR.First;
while not cdsTermosR.Eof do
begin
  if cdsTermosR.Recno > 1 then sql := sql + Condicao;
  sql := sql + ´RP like ´+quotedstr(´¬´+cdsTermosRTERMO.AsString+´¬´);
  cdsTermosR.Next;
end;

desta forma quem está efetuando a consulta decide como quer a busca


Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar