sql ORDER BY vários valores em ordem específica?

94

Ok, eu tenho uma tabela com uma chave indexada e um campo não indexado. Preciso encontrar todos os registros com um determinado valor e retornar a linha. Gostaria de saber se posso pedir por vários valores.

Exemplo:

id     x_field
--     -----
123    a
124    a
125    a
126    b
127    f
128    b
129    a
130    x
131    x
132    b
133    p
134    p
135    i

pseudo: gostaria que os resultados fossem ordenados assim, where ORDER BY x_field = 'f', 'p', 'i', 'a'

SELECT *
FROM table
WHERE id NOT IN (126)
ORDER BY x_field 'f', 'p', 'i', 'a'

Portanto, os resultados seriam:

id     x_field
--     -----
127    f
133    p
134    p
135    i
123    a
124    a
125    a
129    a

A sintaxe é válida, mas quando executo a consulta, ela nunca retorna nenhum resultado, mesmo se eu limitar a 1 registro. Existe outra maneira de fazer isso?

Pense no x_field como resultados de teste e eu preciso validar todos os registros que se enquadram na condição. Eu queria ordenar os resultados do teste por valores com falha, valores aprovados. Portanto, eu poderia validar os valores com falha primeiro e, em seguida, os valores passados ​​usando o ORDER BY.

O que não posso fazer:

  • GROUP BY, pois preciso retornar os valores de registro específicos
  • ONDE x_field IN ('f', 'p', 'i', 'a'), preciso de todos os valores, pois estou tentando usar uma consulta para vários testes de validação. E os valores x_field não estão na ordem DESC / ASC

Depois de escrever essa pergunta estou começando a pensar que preciso repensar isso, LOL!

Phill Pafford
fonte
Em vez disso, talvez um sindicato? Construa consultas separadas na ordem em que deseja que os resultados sejam retornados e, em seguida, faça uma união dessas consultas?
kinakuta

Respostas:

180
...
WHERE
   x_field IN ('f', 'p', 'i', 'a') ...
ORDER BY
   CASE x_field
      WHEN 'f' THEN 1
      WHEN 'p' THEN 2
      WHEN 'i' THEN 3
      WHEN 'a' THEN 4
      ELSE 5 --needed only is no IN clause above. eg when = 'b'
   END, id
gbn
fonte
29

Você pode usar um LEFT JOIN com "VALUES ('f', 1), ('p', 2), ('a', 3), ('i', 4)" e usar a segunda coluna em seu pedido -por expressão. O Postgres usará um Hash Join que será muito mais rápido do que um CASE enorme se você tiver muitos valores. E é mais fácil de gerar automaticamente.

Se essas informações de pedido forem fixas, ela deverá ter sua própria tabela.

bobflux
fonte
6
Esta é de longe a solução mais elegante!
jnns
26

Experimentar:

ORDER BY x_field='F', x_field='P', x_field='A', x_field='I'

Você estava no caminho certo, mas ao colocar x_field apenas no valor F, os outros 3 foram tratados como constantes e não comparados com nada no conjunto de dados.

Marc B
fonte
O Postgres suporta booleano implícito? Em caso afirmativo, como o booleano classifica?
gbn
Gostei dessa solução, mas não retornou nada.
Phill Pafford
@gbn, Sim e falso <verdadeiro. Eu esperava que isso funcionasse.
Andrew Lazarus
6
Sim, funciona evento no Postgres. Nota para esta solução é que você obtém os resultados classificados na ordem inversa. Portanto, você deve colocar os campos na ordem inversa: ORDER BY x_field = 'A', x_field = 'I', x_field = 'P', x_field = 'F',
igo
16

Use uma casechave para traduzir os códigos em números que podem ser classificados:

ORDER BY
  case x_field
  when 'f' then 1
  when 'p' then 2
  when 'i' then 3
  when 'a' then 4
  else 5
  end
Guffa
fonte
10

Encontrei uma solução muito mais limpa para isso:

ORDER BY array_position(ARRAY['f', 'p', 'i', 'a']::varchar[], x_field)

Observação: array_position precisa do Postgres v9.5 ou superior.

rept
fonte
1
É importante notar que array_position () está disponível apenas no Postgres v9.5 em diante, afaik.
ver mais de
obrigado, muito preferido isso aos métodos CASE. Funciona com inteiros também; array_position(ARRAY[1, 0]::integer[], x_field)
Paul Watson
7

As sugestões CASEe ORDER BYdevem funcionar, mas vou sugerir um cavalo de uma cor diferente. Supondo que haja apenas um número razoável de valores para x_fielde você já sabe quais são, crie um tipo enumerado com F, P, A e I como os valores (além de quaisquer outros valores possíveis aplicáveis). Enums serão classificados na ordem indicada por sua CREATEdeclaração. Além disso, você pode usar nomes de valor significativos - seu aplicativo real provavelmente usa e você acabou de mascará-los para confidencialidade - sem desperdiçar espaço, uma vez que apenas a posição ordinal é armazenada.

Andrew Lazarus
fonte
1

Você pode ordenar por uma coluna selecionada ou outras expressões.

Aqui está um exemplo de como ordenar pelo resultado de uma instrução case:

  SELECT col1
       , col2
    FROM tbl_Bill
   WHERE col1 = 0
ORDER BY -- order by case-statement
    CASE WHEN tbl_Bill.IsGen = 0 THEN 0
         WHEN tbl_Bill.IsGen = 1 THEN 1
         ELSE 2 END

O resultado será uma lista começando com "IsGen = 0" linhas, seguido por "IsGen = 1" linhas e todas as outras linhas no final.

Você pode adicionar mais parâmetros de pedido no final:

  SELECT col1
       , col2
    FROM tbl_Bill
   WHERE col1 = 0
ORDER BY -- order by case-statement
    CASE WHEN tbl_Bill.IsGen = 0 THEN 0
         WHEN tbl_Bill.IsGen = 1 THEN 1
         ELSE 2 END,
         col1,
         col2
Código
fonte
Embora este trecho de código possa resolver o problema, ele não explica por que ou como responde à pergunta. Por favor incluir uma explicação para o seu código , como o que realmente ajuda a melhorar a qualidade do seu post. Lembre-se de que você está respondendo à pergunta para leitores no futuro e essas pessoas podem não saber os motivos de sua sugestão de código.
Samuel Philipp
0

Para alguém que é novo no ORDER BY com CASE, isso pode ser útil

ORDER BY 
    CASE WHEN GRADE = 'A' THEN 0
         WHEN GRADE = 'B' THEN 1
         ELSE 2 END
Akitha_MJ
fonte
-2

você pode usar a posição (texto no texto) para ordenar a sequência

Mukesh Kulal
fonte