146 votes

Classement par l'ordre des valeurs dans une clause SQL IN()

Je me demande s'il existe un moyen (peut-être meilleur) d'ordonner les valeurs dans une clause IN().

Le problème est que j'ai 2 requêtes, une qui obtient tous les ID et la seconde qui récupère toutes les informations. La première crée l'ordre des identifiants que je veux que la seconde ordonne. Les identifiants sont placés dans une clause IN() dans l'ordre correct.

Ce serait donc quelque chose comme (extrêmement simplifié) :

SELECT id FROM table1 WHERE ... ORDER BY display_order, name

SELECT name, description, ... WHERE id IN ([id's from first])

Le problème est que la deuxième requête ne renvoie pas les résultats dans le même ordre que celui dans lequel les ID sont placés dans la clause IN().

Une solution que j'ai trouvée est de placer tous les ID dans une table temporaire avec un champ à incrémentation automatique qui est ensuite joint à la deuxième requête.

Y a-t-il une meilleure option ?

Note : Comme la première requête est exécutée "par l'utilisateur" et que la seconde est exécutée en arrière-plan, il n'y a aucun moyen de combiner les deux en une seule requête en utilisant des sous-requêtes.

J'utilise MySQL, mais je pense qu'il pourrait être utile d'indiquer les options disponibles pour les autres bases de données.

180voto

ʞɔıu Points 15907

Utilisez la fonction FIELD() función:

SELECT name, description, ...
FROM ...
WHERE id IN([ids, any order])
ORDER BY FIELD(id, [ids in order])

FIELD() retournera l'index du premier paramètre qui est égal au premier paramètre (autre que le premier paramètre lui-même).

FIELD('a', 'a', 'b', 'c')

retournera 1

FIELD('a', 'c', 'b', 'a')

retournera 3

Cela donnera exactement ce que vous voulez si vous collez les identifiants dans la clause IN() et la fonction FIELD() dans le même ordre.

15voto

Pradeep Singh Points 31

Voir ci-dessous comment obtenir des données triées.

SELECT ...
  FROM ...
 WHERE zip IN (91709,92886,92807,...,91356)
   AND user.status=1
ORDER 
    BY provider.package_id DESC 
     , FIELD(zip,91709,92886,92807,...,91356)
LIMIT 10

11voto

John Nilsson Points 4650

Deux solutions qui me viennent à l'esprit :

  1. order by case id when 123 then 1 when 456 then 2 else null end asc

  2. order by instr(','||id||',',',123,456,') asc

( instr() vient d'Oracle ; vous avez peut-être locate() o charindex() ou quelque chose comme ça)

4voto

Jonathan Leffler Points 299946

La clause IN décrit un ensemble de valeurs, et les ensembles n'ont pas d'ordre.

Votre solution avec une jointure et ensuite la commande sur le display_order est la solution la plus proche de la réalité ; toute autre solution est probablement un piratage spécifique au SGBD (ou une utilisation des fonctions OLAP dans le SQL standard). La jointure est certainement la solution la plus proche de la portabilité (bien que la génération des données avec la fonction display_order peuvent être problématiques). Notez que vous devrez peut-être sélectionner les colonnes de classement ; c'était une exigence du SQL standard, mais je crois que cette règle a été assouplie il y a quelque temps (peut-être même depuis SQL-92).

2voto

Sarthak Sawhney Points 75

Utilisez FIND_IN_SET :

  SELECT * 
    FROM table_name 
   WHERE id IN (..,..,..,..) 
ORDER BY FIND_IN_SET (coloumn_name, .., .., ..);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X