Ordenação - SQL
02/06/2008
0
Amigos(as), tenho uma tela onde o usuário digita uma determinada queixa e o sistema faz a busca, mostrando os dados no grid.
Primeiramente, estou utilizando delphi 2006 + dbxpress + sqlserver 2000
A rotina é a seguinte:
procedure TfrmQueixas.PesquisaQueixa(vQtde : integer);
begin
with cdsPesquisaQueixa do
begin
close;
CommandText := ´´;
CommandText := ´ SELECT CF_QUEI_COD, CF_QUEI_NOM, ´ +
´ CF_QUEI_CRI_USU, CF_QUEI_CRI_DAT, ´ +
´ CF_QUEI_UAL_USU, CF_QUEI_UAL_DAT, ´ +
´ CF_QUEI_UAC_USU, CF_QUEI_UAC_DAT ´ +
´ FROM CONF_QUEIXA ´;
// vQtde = 0 - Traz todos os registros
// vQtde = 1 - Traz apenas alguns (condição)
if vQtde = 0 then
CommandText := CommandText + ´ ORDER BY CF_QUEI_NOM´
else
CommandText := CommandText + ´ WHERE CF_QUEI_NOM LIKE ´ + QuotedStr(edtQueixa.Text + ´¬´) +
//´ OR CF_QUEI_NOM LIKE ´ + QuotedStr(´¬´ + ´ ´ + edtQueixa.Text + ´ ´ + ´¬´) +
´ OR CF_QUEI_NOM LIKE ´ + QuotedStr(´¬´ + ´ ´ + edtQueixa.Text + ´¬´) +
´ OR CF_QUEI_NOM LIKE ´ + QuotedStr(´¬´ + edtQueixa.Text) +
´ ORDER BY CF_QUEI_NOM´;
open;
if IsEmpty then
begin
edtQueixa.SetFocus;
close;
Application.MessageBox(´Queixa não localizada´, ´Informação´, MB_OK + MB_ICONINFORMATION);
ControlaItensPopup(1); // Desabilita Itens do Poupop
exit;
end
else
begin
btnSelecionar.Enabled := true;
ControlaItensPopup(0); // Habilita Itens do Poupop
end;
end;
end;
Até aí tranquilo. O grande problema está na ordenação, que deve ser feita da seguinte forma:
- ordenar os que começam, por exemplo, por febre; em seguida, por contenham febre, e por último, q terminam por febre.
- Ao invés disso
aa febre
aa febre bbbb
febre
c febre
febre aaaaaa
- Isso
febre
febre aaaaaa
aa febre bbbb
aa febre
c febre
Parece complicado, mas preciso fazer ordenar os dados dessa maneira, e estou encontrando dificuldade para isso.
Fico no aguardo, e qualquer sugestão será bem-vinda.
[]´s
Roger1976
Posts
02/06/2008
Emerson Nascimento
procedure TfrmQueixas.PesquisaQueixa(vQtde : integer); var queixa: string; begin queixa := Trim(edtQueixa.Text); with cdsPesquisaQueixa do begin close; strSQL := ´SELECT ´+ ´ (case ´+ ´ when CF_QUEI_NOM like ´+QuotedStr(queixa+´¬´)+´ then ´´0´´ ´+ // inicia ´ when CF_QUEI_NOM like ´+QuotedStr(´¬ ´+queixa+´ ¬´)+´ then ´´1´´ ´+ // contém ´ when CF_QUEI_NOM like ´+QuotedStr(´¬´+queixa)+´ then ´´2´´ ´+ // termina ´ end) ORDEM, ´+ // campo virtual para correta ordenação dos registros ´ CF_QUEI_COD, CF_QUEI_NOM, ´+ ´ CF_QUEI_CRI_USU, CF_QUEI_CRI_DAT, ´+ ´ CF_QUEI_UAL_USU, CF_QUEI_UAL_DAT, ´+ ´ CF_QUEI_UAC_USU, CF_QUEI_UAC_DAT ´+ ´FROM ´+ ´ CONF_QUEIXA ´; // vQtde = 0 - Traz todos os registros // vQtde = 1 - Traz apenas alguns (condição) if vQtde = 0 then strSQL := strSQL + ´ ORDER BY CF_QUEI_NOM´ else strSQL := strSQL + ´WHERE CF_QUEI_NOM LIKE ´ + QuotedStr(edtQueixa.Text + ´¬´) + // inicia ´ OR CF_QUEI_NOM LIKE ´ + QuotedStr(´¬ ´ + edtQueixa.Text + ´ ¬´) + // contém ´ OR CF_QUEI_NOM LIKE ´ + QuotedStr(´¬´ + edtQueixa.Text) + // termina ´ ORDER BY 1, CF_QUEI_NOM´; CommandText := strSQL; Open; if IsEmpty then begin edtQueixa.SetFocus; close; Application.MessageBox(´Queixa não localizada´, ´Informação´, MB_OK + MB_ICONINFORMATION); ControlaItensPopup(1); // Desabilita Itens do Poupop end else begin btnSelecionar.Enabled := true; ControlaItensPopup(0); // Habilita Itens do Poupop end; end; end;
[b:41c8748e7c]note que o campo ORDEM não precisa ser exibido.[/b:41c8748e7c]
02/06/2008
Roger1976
lembra:
febre
febre aaaaaa
aa febre bbbb
aa febre
c febre
Seguindo o seu código, ele só está trazendo:
febre
febre aaaaaa
Vou dar umas fuçadas aki, caso tenha outra sugestão, será bem-vinda.
Muito obrigado pela dica.
[]s
02/06/2008
Emerson Nascimento
procedure TfrmQueixas.PesquisaQueixa(vQtde : integer); var queixa: string; begin queixa := Trim(edtQueixa.Text); with cdsPesquisaQueixa do begin close; strSQL := ´SELECT ´+ ´ (case ´+ ´ when CF_QUEI_NOM like ´´<queixa>¬´´ then ´´0´´ ´+ // inicia ´ when CF_QUEI_NOM like ´´¬ <queixa> ¬´´ then ´´1´´ ´+ // contém ´ when CF_QUEI_NOM like ´´¬<queixa>´´ then ´´2´´ ´+ // termina ´ end) ORDEM, ´+ // campo virtual para correta ordenação dos registros ´ CF_QUEI_COD, CF_QUEI_NOM, ´+ ´ CF_QUEI_CRI_USU, CF_QUEI_CRI_DAT, ´+ ´ CF_QUEI_UAL_USU, CF_QUEI_UAL_DAT, ´+ ´ CF_QUEI_UAC_USU, CF_QUEI_UAC_DAT ´+ ´FROM ´+ ´ CONF_QUEIXA ´; // vQtde = 0 - Traz todos os registros // vQtde = 1 - Traz apenas alguns (condição) if vQtde = 0 then strSQL := strSQL + ´ ORDER BY CF_QUEI_NOM´ else strSQL := strSQL + ´WHERE (CF_QUEI_NOM LIKE ´´<queixa>¬´´) ´ + // inicia ´ OR (CF_QUEI_NOM LIKE ´´¬ <queixa> ¬´´) ´ + // contém ´ OR (CF_QUEI_NOM LIKE ´´¬<queixa>´´) ´ + // termina ´ ORDER BY 1, CF_QUEI_NOM´; CommandText := StringReplace(strSQL, ´<queixa>´, queixa, [rfReplaceAll]); Open; if IsEmpty then begin edtQueixa.SetFocus; close; Application.MessageBox(´Queixa não localizada´, ´Informação´, MB_OK + MB_ICONINFORMATION); ControlaItensPopup(1); // Desabilita Itens do Poupop end else begin btnSelecionar.Enabled := true; ControlaItensPopup(0); // Habilita Itens do Poupop end; end; end;
nos meus testes funcionou perfeitamente...
.
03/06/2008
Roger1976
olha, eu não estou em casa, não tenho como testar agora, mas vou pedir para um amigo que está passando pelo mesmo problema testar, e aí te retorno.
Obrigado pela força.
[]s
03/06/2008
Bico
Tente da seguinte forma e vê se pode ser solucionado assim:
SELECT ´1´"ORDEM", CF_QUEI_COD, CF_QUEI_NOM, CF_QUEI_CRI_USU, CF_QUEI_CRI_DAT, CF_QUEI_UAL_USU, CF_QUEI_UAL_DAT, CF_QUEI_UAC_USU, CF_QUEI_UAC_DAT FROM CONF_QUEIXA WHERE UPPER(CF_QUEI_NOM) LIKE UPPER(´febre¬´) UNION SELECT ´2´"ORDEM", CF_QUEI_COD, CF_QUEI_NOM, CF_QUEI_CRI_USU, CF_QUEI_CRI_DAT, CF_QUEI_UAL_USU, CF_QUEI_UAL_DAT, CF_QUEI_UAC_USU, CF_QUEI_UAC_DAT FROM CONF_QUEIXA WHERE UPPER(CF_QUEI_NOM) LIKE UPPER(´¬ febre¬´) UNION SELECT ´3´"ORDEM", CF_QUEI_COD, CF_QUEI_NOM, CF_QUEI_CRI_USU, CF_QUEI_CRI_DAT, CF_QUEI_UAL_USU, CF_QUEI_UAL_DAT, CF_QUEI_UAC_USU, CF_QUEI_UAC_DAT FROM CONF_QUEIXA WHERE UPPER(CF_QUEI_NOM) LIKE UPPER(´¬ febre´) ORDER BY 1
Não testei com a estrutura da sua tabela, testei em uma tabela de pessoas que tenho aqui. Pode ser que tenha algum erro de sintaxe no SQL que montei com base na sua tabela. Por este motivo segue a minha consulta, testada e funcionando:
SELECT ´1´"ORDEM", P.COD_ALT, P.RAZ_SOC FROM PESSOA P WHERE UPPER(P.RAZ_SOC) LIKE UPPER(´fernando¬´) UNION SELECT ´2´"ORDEM", P.COD_ALT, P.RAZ_SOC FROM PESSOA P WHERE UPPER(P.RAZ_SOC) LIKE UPPER(´¬ fernando¬´) UNION SELECT ´3´"ORDEM", P.COD_ALT, P.RAZ_SOC FROM PESSOA P WHERE UPPER(P.RAZ_SOC) LIKE UPPER(´¬ fernando´) ORDER BY 1
Atenciosamente,
Fernando.
03/06/2008
Emerson Nascimento
a linha onde consta [i:aedb617a29]ORDER BY 1, CF_QUEI_NOM[/i:aedb617a29] só será utilizada caso seja passado um critério de busca (assim como no seu exemplo). se buscar por tudo, o ordenação será somente pelo campo CF_QUEI_NOM.
veja que isso é definido pelo if, da mesma forma que você exibiu no seu código:
// vQtde = 0 - Traz todos os registros // vQtde = 1 - Traz apenas alguns (condição) if vQtde = 0 then strSQL := strSQL + ´ ORDER BY CF_QUEI_NOM´ else strSQL := strSQL + ´WHERE CF_QUEI_NOM LIKE ´ + QuotedStr(Queixa+ ´¬´) + // inicia ´ OR CF_QUEI_NOM LIKE ´ + QuotedStr(´¬ ´+Queixa+´ ¬´) + // contém ´ OR CF_QUEI_NOM LIKE ´ + QuotedStr(´¬´+Queixa) + // termina ´ ORDER BY 1, CF_QUEI_NOM´;
o exemplo do colega Bico com certeza funciona. é exatamente o mesmo comando que eu passei, porém ele o fez em três passos, com union (performance menor) e eu fiz em apenas um.
mas tem um pequeno problema nos dois últimos selects do Bico, pois eles poderão trazer os mesmos registros. por isso na minha instrução está assim:
QuotedStr(Queixa+´¬´) + // inicia (sem espaço)
QuotedStr(´¬ ´+Queixa+´ ¬´) + // contém (há um espaço antes e um depois de Queixa)
QuotedStr(´¬´+Queixa) + // termina (sem espaço)
03/06/2008
Emerson Nascimento
1- sem critério de busca:
SELECT (case when CF_QUEI_NOM like ´¬´ then ´0´ when CF_QUEI_NOM like ´¬ ¬´ then ´1´ when CF_QUEI_NOM like ´¬´ then ´2´ end) ORDEM, CF_QUEI_COD, CF_QUEI_NOM, CF_QUEI_CRI_USU, CF_QUEI_CRI_DAT, CF_QUEI_UAL_USU, CF_QUEI_UAL_DAT, CF_QUEI_UAC_USU, CF_QUEI_UAC_DAT FROM CONF_QUEIXA ORDER BY CF_QUEI_NOM
2 - ao buscar por [i:a0e6f08408]febre[/i:a0e6f08408]:
SELECT (case when CF_QUEI_NOM like ´febre¬´ then ´0´ when CF_QUEI_NOM like ´¬ febre ¬´ then ´1´ when CF_QUEI_NOM like ´¬febre´ then ´2´ end) ORDEM, CF_QUEI_COD, CF_QUEI_NOM, CF_QUEI_CRI_USU, CF_QUEI_CRI_DAT, CF_QUEI_UAL_USU, CF_QUEI_UAL_DAT, CF_QUEI_UAC_USU, CF_QUEI_UAC_DAT FROM CONF_QUEIXA WHERE (CF_QUEI_NOM LIKE ´febre¬´) OR (CF_QUEI_NOM LIKE ´¬ febre ¬´) OR (CF_QUEI_NOM LIKE ´¬febre´) ORDER BY 1, CF_QUEI_NOM ORDER BY 1, CF_QUEI_NOM
teste as instruções no Query Analizer e veja se funciona.
03/06/2008
Emerson Nascimento
03/06/2008
Brunodsr
A solução do nosso emerson.en resolve o seu problema mas talvez comprometa a performance da sua pesquisa por conta do ´OR´, o que faz com que a query ignore os índices do banco.
Eu sugiro que vc faça três queries diferentes dentro de uma procedure e os parametros que vc passaria para a query, passa para a procedure.
Criacao da procedure:
/* PLSQL - verifique a sintaxe do seu banco de dados */ Procedure cTeste; as declare num, xx (variaveis) /* primeira query */ for select 1, tabela.* from tabela where campo like ´abc¬´ into num, xx do return; /* segunda query */ for select 2, tabela.* from tabela where campo like ´¬abc¬´ into num, xx do return; /* terceira query */ for select 3, tabela.* from tabela where campo like ´¬abc´ into num, xx do return; end.
Daí vc faz um select diretamente na procedure.
select * from procedure(´param1´,´param2´) order by num, xxx
Com isso daí vc vai respeitar os seus índices e vai ter o mesmo retorno.
Espero ter ajudado.
03/06/2008
Emerson Nascimento
não, não...
utiliza os índices sim.
o SQL Server tem um mecanismo que interpreta a instrução e a monta de forma que, na medida do possível, os índices sejam utilizados.
se você rodar essa instrução no Query Analizer e exibir o plano de execução, verá que o mecanismo remonta a instrução de forma a ter a melhor performance possível.
tavez o mecanismo do Firebird tenha essa ´brecha´, mas o do SQL Server não tem.
04/06/2008
Brunodsr
Achei que fosse padrão de todos os bancos rodar fora dos índices com OR e UNION.
Aqui no trabalho usamos Oracle e Informix. E a instrução passada pelos DBAs é que não usemos o OR e Union, exceto em ultimo caso. Já tive que rodar muito p/ otimizar algumas queries. Putz..
Vc sabe se isso procede??
Um abraço
06/06/2008
Roger1976
Desculpem-me mais uma vez, e agradeço muito pela boa vontade de todos em me ajudar nesta solução, foi um ótimo aprendizado.
[]´s
06/06/2008
Roger1976
07/06/2008
Emerson Nascimento
08/06/2008
Roger1976
procedure TfrmQueixas.btnProcurarClick(Sender: TObject);
begin
case Length(edtQueixa.Text)of
0 : PesquisaQueixa(0);
3 : PesquisaQueixa(1);
end
end;
- Código da procedure PesquisaQueixa:
procedure TfrmQueixas.PesquisaQueixa(vQtde : integer);
begin
with cdsPesquisaQueixa do
begin
close;
CommandText :=
´SELECT ´+
´ (case ´+
´ when CF_QUEI_NOM like ´ + QuotedStr(edtQueixa.Text + ´¬´) + ´ then ´´0´´ ´+ // inicia
´ when CF_QUEI_NOM like ´ + QuotedStr(´¬ ´ + edtQueixa.Text + ´ ¬´) + ´ then ´´1´´ ´+ // contém
´ when CF_QUEI_NOM like ´ + QuotedStr(´¬´ + edtQueixa.Text) + ´ then ´´2´´ ´+ // termina
´ end) ORDEM, ´+ // campo virtual para correta ordenação dos registros
´ CF_QUEI_COD, CF_QUEI_NOM, ´+
´ CF_QUEI_CRI_USU, CF_QUEI_CRI_DAT, ´+
´ CF_QUEI_UAL_USU, CF_QUEI_UAL_DAT, ´+
´ CF_QUEI_UAC_USU, CF_QUEI_UAC_DAT ´+
´FROM ´+
´ CONF_QUEIXA ´;
// vQtde = 0 - Traz todos os registros
// vQtde = 1 - Traz apenas alguns (condição)
if vQtde = 0 then
CommandText := CommandText + ´ ORDER BY CF_QUEI_NOM´
else
CommandText := CommandText +
´ WHERE (CF_QUEI_NOM LIKE ´ + QuotedStr(edtQueixa.Text + ´¬´) + ´) ´ + // inicia
´ OR (CF_QUEI_NOM LIKE ´ + QuotedStr(´¬ ´+ edtQueixa.Text + ´ ¬´) + ´) ´ + // contém
´ OR (CF_QUEI_NOM LIKE ´ + QuotedStr(´¬´ + edtQueixa.Text) + ´) ´ + // termina
´ ORDER BY 1, CF_QUEI_NOM´;
Open;
if IsEmpty then
begin
edtQueixa.SetFocus;
close;
Application.MessageBox(´Queixa não localizada´, ´Informação´, MB_OK + MB_ICONINFORMATION);
ControlaItensPopup(1); // Desabilita Itens do Poupop
end
else
begin
btnSelecionar.Enabled := true;
ControlaItensPopup(0); // Habilita Itens do Poupop
end;
end;
end;
Basicamente, foi o que vc tinha me passado anteriormente, porém fiz pequenas alterações, nada de mais.
Clique aqui para fazer login e interagir na Comunidade :)