Ordonner l’union ou unir l’ordre?

Disons que nous avons une table yo comportant les colonnes meh et mih. Disons aussi que nous voulons avoir le premier et le dernier record de cette table, ordonné par meh.

Séparément, en sqlite3, on aurait

select * from yo order by meh asc limit 1;

pour le premier, et

select * from yo order by meh desc limit 1;

pour le dernier.

Bon, il ne reste plus qu’à faire une union alors:

select * from yo order by meh asc limit 1 union all select * from yo order by meh desc limit 1;

Et bien non. Sur sqlite3, on reçoit l’erreur:

SQL error: ORDER BY clause should come after UNION ALL not before

D’abord, joli manque de ponctuation, mais ensuite, pourquoi cela?, se dit-on. Quand on y pense purement du côté de l’union, il ne fait effectivement aucun sens d’ordonner les éléments des 2 tables dès le début — on ordonnerait plutôt après l’union. Le problème ici est que je ne veux pas ordonner le résultat de mon union, mais plutôt unir 2 résultats ordonnés. Aussi, on ne saurait dire si le dernier order by servirait à ordonner la deuxième table, ou bien à ordonner le résultat de l’union.

Et non, on ne peut pas faire:

(select * from yo order by meh asc limit 1) union all (select * from yo order by meh desc limit  1);

Ça serait trop facile. Si j’ai pensé à mettre ces parenthèses, c’est peut-être parce que je m’obstine à penser que SQL est un langage simple à utiliser…

Un compagnon de travail m’a fait part du blog de Pinal Dave, http://blog.sqlauthority.com, où dans un de ses posts parle justement de ce problème. La solution rapide de Pinal ressemblait à:

select * from yo where meh in(
select min(meh) from yo union all
select max(meh) from yo
);

Je ne trouve pas que c’est très élégant, en plus de peut-être donner plus de 2 lignes de résultats si les valeurs de “meh” ne sont pas distinctes.

Je suis déjà nostalgique envers ma solution avec des parenthèses, et je vois un commentaire de Dave Arthur au post de Pinal utilisant cette solution, mais d’un moyen correct, soit:

select a.* from (
  select * from yo order by meh asc limit 1
) a
union all
select b.* from (
  select * from yo order by meh desc limit 1
) b

C’est la joie. Je trouve cela complètement stupide et redondant, mais ça colle déjà mieux avec l’idée initiale. De plus, on peut facilement changer le nombre de lignes des 2 queries, séparément.

Leave a Reply