sql ORDER BY plusieurs valeurs dans un ordre spécifique?


94

Ok j'ai une table avec une clé indexée et un champ non indexé. Je dois trouver tous les enregistrements avec une certaine valeur et renvoyer la ligne. Je voudrais savoir si je peux commander par valeurs multiples.

Exemple:

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: souhaite que les résultats soient classés comme ceci, 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'

Les résultats seraient donc:

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

La syntaxe est valide mais lorsque j'exécute la requête, elle ne renvoie aucun résultat, même si je la limite à 1 enregistrement. Y a-t-il une autre façon de procéder?

Considérez le champ x comme des résultats de test et j'ai besoin de valider tous les enregistrements qui correspondent à la condition. Je voulais ordonner les résultats du test par valeurs échouées, valeurs passées. Je pourrais donc valider les valeurs ayant échoué en premier, puis les valeurs passées en utilisant ORDER BY.

Ce que je ne peux pas faire:

  • GROUP BY, car je dois renvoyer les valeurs d'enregistrement spécifiques
  • WHERE x_field IN ('f', 'p', 'i', 'a'), j'ai besoin de toutes les valeurs car j'essaie d'utiliser une requête pour plusieurs tests de validation. Et les valeurs x_field ne sont pas dans l'ordre DESC / ASC

Après avoir écrit cette question, je commence à penser que je dois repenser cela, LOL!


Peut-être plutôt un syndicat? Construisez des requêtes séparées dans l'ordre dans lequel vous voulez que les résultats soient renvoyés, puis effectuez une union de ces requêtes?
kinakuta

Réponses:


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

29

Vous pouvez utiliser une jointure à gauche avec "VALUES ('f', 1), ('p', 2), ('a', 3), ('i', 4)" et utiliser la deuxième colonne dans votre commande -par expression. Postgres utilisera un Hash Join qui sera bien plus rapide qu'un énorme CASE si vous avez beaucoup de valeurs. Et il est plus facile de générer automatiquement.

Si ces informations de commande sont fixes, elles doivent avoir leur propre table.


6
C'est de loin la solution la plus élégante!
jnns

28

Essayer:

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

Vous étiez sur la bonne voie, mais en mettant x_field uniquement sur la valeur F, les 3 autres ont été traités comme des constantes et non comparés à quoi que ce soit dans le jeu de données.


Postgres prend-il en charge le booléen implicite? Si oui, comment le tri booléen?
gbn le

J'ai aimé cette solution mais elle n'a rien retourné.
Phill Pafford

@gbn, Oui et faux <vrai. Je me serais attendu à ce que cela fonctionne.
Andrew Lazarus

7
Oui, cela fonctionne événement dans Postgres. Notez à cette solution que vous obtenez le résultat trié dans l'ordre inverse. Vous devez donc mettre les champs dans l'ordre inverse: ORDER BY x_field = 'A', x_field = 'I', x_field = 'P', x_field = 'F',
igo

16

Utilisez un casecommutateur pour traduire les codes en nombres qui peuvent être triés:

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

10

J'ai trouvé une solution beaucoup plus propre pour cela:

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

Remarque: array_position nécessite Postgres v9.5 ou supérieur.


1
Il est important de noter que array_position () n'est disponible que dans Postgres v9.5, afaik.
bigsee

merci beaucoup préféré aux méthodes CASE. Fonctionne aussi avec des entiers; array_position(ARRAY[1, 0]::integer[], x_field)
Paul Watson

7

Les suggestions CASEet ORDER BYdevraient toutes fonctionner, mais je vais suggérer un cheval d'une couleur différente. En supposant qu'il n'existe qu'un nombre raisonnable de valeurs pour x_fieldet que vous savez déjà ce qu'elles sont, créez un type énuméré avec F, P, A et I comme valeurs (plus toutes les autres valeurs possibles applicables). Les énumérations seront triées dans l'ordre implicite de leur CREATEinstruction. En outre, vous pouvez utiliser des noms de valeur signifiants - votre application réelle le fait probablement et vous venez de les masquer pour des raisons de confidentialité - sans gaspiller d'espace, car seule la position ordinale est stockée.


1

Vous pouvez trier selon une colonne sélectionnée ou d'autres expressions.

Voici un exemple, comment classer par le résultat d'une instruction de cas:

  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

Le résultat sera une liste commençant par les lignes «IsGen = 0», suivies par les lignes «IsGen = 1» et toutes les autres lignes à la fin.

Vous pouvez ajouter plus de paramètres de commande à la fin:

  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

Bien que cet extrait de code puisse résoudre le problème, il n'explique pas pourquoi ni comment il répond à la question. Veuillez inclure une explication de votre code , car cela contribue vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondez à la question aux lecteurs à l'avenir, et que ces personnes pourraient ne pas connaître les raisons de votre suggestion de code.
Samuel Philipp

0

Pour quelqu'un qui est nouveau ORDER BY avec CASE, cela peut être utile

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

-2

vous pouvez utiliser la position (texte dans le texte) dans l'ordre pour ordonner la séquence

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.