Consulta aproximada (tipo google, forum, etc...)
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!
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
Curtidas 0
Respostas
Weber
07/02/2007
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.
GOSTEI 0
Mahdak
07/02/2007
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!
GOSTEI 0
Emerson Nascimento
07/02/2007
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].
GOSTEI 0
Mahdak
07/02/2007
creio que a dica do Weber funciona:
(pressupondo que você já separou as palavras do edit num array ou num stringlist)
[/b] por [b:d7370fc152]or[/b:d7370fc152].
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;
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!!!
GOSTEI 0
Emerson Nascimento
07/02/2007
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:
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).
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).
GOSTEI 0
Mahdak
07/02/2007
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!
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!
GOSTEI 0
Emerson Nascimento
07/02/2007
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.
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.
GOSTEI 0
Mahdak
07/02/2007
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...
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 é:
quando deveria ser:
pode me ajudar com isso???
um abração
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
GOSTEI 0
Mahdak
07/02/2007
resolvido... foi só dar last e prior pra mandar o registro se mover....
[]´s
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
GOSTEI 0
Emerson Nascimento
07/02/2007
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´)
ou você pode permitir a busca por ao menos um dos termos, fazendo assim:
desta forma quem está efetuando a consulta decide como quer a busca
(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
GOSTEI 0