SQL: Tri multicolonnes

Le problème exposé dans ce sujet a été résolu.

Bonjour,

JE simplifie évidemment énormément le cas concret, mais admettons qu’on ait la table suivante avec ses données:

create table test (
id int not null,
nom1 varchar(255),
nom2 varchar(255),
primary key(id));

insert into test
(id, nom1, nom2)
values
(1, 'Elodie', null),
(2, null, 'David'),
(3, null, 'Bob'),
(4, 'Alice', null),
(5, 'Cedric', null);

Existe-t-il une requête pour me retourner les données triées par ordre alphabétique à la fois sur nom1 et nom2 ?

select id, nom1, nom2 from test
order by ??????

J’aimerais obtenir:

id, nom1, nom2
4, Alice, null
3, null, Bob
5, Cedric, null
2, null, David
1, Elodie, null

Sachant que pour une entrée donnée, une seule des deux colonnes nom1 et nom2 ne sont remplies à la fois tandis que l’autre est nécessairement null. Nom1 et nom2 ne peuvent pas être remplies en même temps, et il ne peut pas y avoir non plus d’entrée avec deux fois null.

Ce serait évidemment beaucoup plus simple d’avoir tout dans une seule et même colonne, mais ça, ce n’est pas moi qui l’ai choisi et je ne peux pas le changer (dans le cas réel, nom1 et nom2 proviennent de jointures sur des tables différentes). Je n’ai pas non plus la possibilité de construire une telle colonne à l’avance (interdiction de changer la structure des données).

Avant de dire que c’est trop facile, la requête suivante par exemple ne donne pas le résultat voulu dans le bon ordre:

select id, nom1, nom2 from test
order by nom1 nulls last, nom2 nulls last;
----------
4, Alice, null
5, Cedric, null
1, Elodie, null
3, null, Bob
2, null, David

Est-ce que je suis condamné à faire le tri après coup dans le langage client (en l’occurence Java dans mon cas, mais ça n’a pas beaucoup d’importance), ou bien est-ce qu’il existe une solution en SQL (si possible non spécifique à un SGBD donné) ?

Question bonus: dans mon cas concret, j’ai trois colonnes nom1, nom2 et nom3, et non pas seulement deux ! Est-ce que c’est toujours faisable ? Toujours avec une seule et unique colonne remplie à la fois et interdiction de modifier la structure existante.

Merci pour vos réponses !

+0 -0

Salut,

C’est du "bricolage" et il y a peut être mieux. Pour ce souci, je concaténerais les deux colonnes pour en faire une seule et ainsi trier dessus.

Avec SQLite tu peux faire quelque chose comme ça :

select id, nom1, nom2, hex(nom1) || hex(nom2) as noms
from test
order by noms

ou si tu ne veux pas afficher la 3ème colonne

select id, nom1, nom2
from test
order by hex(nom1) || hex(nom2)

Ces exemples sont pour SQLite, sinon en SQL tu as la commande CONCAT qui doit fonctionner elle aussi.

J’espère que ça pourra t’avancer :)

+1 -0

+1 aux solutions ci-dessus, et sinon, un fait peu connu : ça peut être plus rapide de faire le tri en langage client qu’en SQL, si tant est que le tri ne soit pas nécessaire au fonctionnement d’une autre partie de la requête (comme dans le cas d’une pagination). C’est par exemple le cas avec Java + PostgreSQL et un tri sur des colonnes non indexées.

+1 aux solutions ci-dessus, et sinon, un fait peu connu : ça peut être plus rapide de faire le tri en langage client qu’en SQL, si tant est que le tri ne soit pas nécessaire au fonctionnement d’une autre partie de la requête (comme dans le cas d’une pagination). C’est par exemple le cas avec Java + PostgreSQL et un tri sur des colonnes non indexées.

C’est bel et bien à cause de la pagination que je veux éviter à tout prix un tri Java, parce que ce serait un bordel à gérer et surtout une catastrophe pour les performances.

Je n’ai pas du tout pensé à la concaténation, et du coup ça lève deux nouvelles questions:

  • A quel point la fonction concat ou l’opérateur || sont disponibles de base p.ex. HQL/JPQL
  • ON est certain de ne pas faire apparaître le mot null dans la colonne concaténée, faussant le tri ? p.ex. "Alicenull" ou "nullBob"

Merci ! Ca m’aide bien en tout cas !

+0 -0

Attention, la fonction coalesce() ci-dessus n’est pas une concaténation – et d’ailleurs il semblerait que concat() ne permette pas de faire ce que tu veux.

Sinon, coalesce() est une fonction de la norme SQL-92… ce qui ne garantit absolument pas son support (cf le lien ci-dessus). En SQL, tu dois partir du principe que dès que tu veux faire quelque chose de non trivial, tu vas avoir des différences insolubles entre les SGBD. Même des cas simples mais non triviaux voient apparaître ce genre de différences, comme par exemple limiter le nombre de résultats envoyés.

il semblerait que concat() ne permette pas de faire ce que tu veux.

Bien vu.

If any of the concatenation values are NULL, the entire returned string is NULL.

Dommage ! Un peu plus et je me faisais avoir.

Du coup je vais partir sur coalesce. De toute façon c’est plus propre que la concaténation. LE seul qui risque de m’embêter c’est H2, visiblement. Tous les autres SGBD qui sont utilisés la supportent bien.

JE ne connaissais pas du tout cette fonction. Merci beaucoup ! Sujet résolu donc.

+2 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte