Ordenação - SQL

02/06/2008

2

Saudações delphianas!!!!


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


Responder

Posts

tente assim:
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]


Responder

02/06/2008

Roger1976

emerson.en, eu fiz um teste e ele só está trazendo o q começa com febre, por exemplo. na verdade, ele tem que trazer todos, a única diferença é a ordem em que esses dados serão selecionados.

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


Responder
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...

.


Responder

03/06/2008

Roger1976

amigo, uma pergunta, quando vc colocar ORDER BY 1, a ordenação não será somente para os que contenham febre, por exemplo?

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


Responder

03/06/2008

Bico

Bom dia colega.

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.


Responder
amigo, uma pergunta, quando vc colocar ORDER BY 1, a ordenação não será somente para os que contenham febre, por exemplo? 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

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)


Responder
para ilustrar melhor, o resutado das instruções deveria ser
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.


Responder
como você deve ter percebido, o segundo exemplo contém duas vezes a linha do ORDER BY.... retire uma delas...


Responder

03/06/2008

Brunodsr

Bom dia!

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.


Responder
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.


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.


Responder

04/06/2008

Brunodsr

Desculpem..

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


Responder

06/06/2008

Roger1976

emerson.en, bico, brunodsr, primeiramente, peço desculpas a todos pois tive um problema de saúde e fiquei de molho, somente agora, já restabelecido, tive condições de voltar ao trabalho. Em cima do que o emerson.en havia me passado anteriormente, fiz testes e só funcionou quando eu removi os espaços da segunda condição (de ´¬ febre ¬´ alterei para ´¬febre´). Se houver um sintoma asdfaFEBREasfasf, este não deverá ser selecionado. Vou verificar NOVAMENTE se não foi o comando trim que utilizei numa comparação para remover os espaços vazios, e já darei a resposta.

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


Responder

06/06/2008

Roger1976

emerson.en, no query analyser funciona perfeita, inclusive a condição ´¬ febre ¬´, já no delphi traz somente registros com a condição ´febre¬´, a não ser que eu remova os espaços da segunda condição, ficando assim: ´¬febre¬´. Só q se eu for buscar ASMA, se eu digitar ASM, aí trará também registros que contenham estas 3 letras.


Responder
publique como você passou a instrução no Delphi...


Responder

08/06/2008

Roger1976

- Código do botão [b:9a5afa4c05]procurar[/b:9a5afa4c05]:

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.


Responder