IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage SQL Discussion :

ORDER BY sur des varchars pour avoir : 1,2,3, ,10,11,12, ,AA,AB,AC


Sujet :

Langage SQL

  1. #1
    Membre du Club
    Profil pro
    Développeur informatique
    Inscrit en
    Mai 2008
    Messages
    100
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2008
    Messages : 100
    Points : 57
    Points
    57
    Par défaut ORDER BY sur des varchars pour avoir : 1,2,3, ,10,11,12, ,AA,AB,AC
    Bonjour,

    J'ai une table avec un champ de type varchar(10).
    Ce champ représente un n° de BD et il peut contenir une valeur entière (1,2,3,...,10,11,12,...) ou une chaîne (HS pour hors-série par exemple).

    Avec un ORDER BY classique, je les récupère dans cet ordre :
    1,10,11,12,...,2,21,...,3,31,...,HS1,HS2,...
    (normal, c'est un varchar)

    Mais je les voudrais comme ça :
    1,2,3,...,10,11,12,...,HS1,HS2,...

    Comment faire ?

    J'ai pensé à enregistrer mes valeurs en base ainsi : 01,02,03,...
    Mais si je passe la barre des 100, le problème se reposera.
    Et en plus j'ai pas trop envie de m'amuser à rajouter un 0 par-ci, ou retirer un 0 par-là selon les cas.

    Merci
    GRULF

  2. #2
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Quel est ton SGBD ?

    Regarde du côté de CAST pour transformer les chaînes en nombres et du côté de CASE pour tester si c'est bien un nombre et ainsi les mettre en premier ordre de tri.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  3. #3
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Avec Oracle, tu peux créer la fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
     
    CREATE OR replace function NATURAL_ORDER(
        P_STR   varchar2
    ) return varchar2
    IS
    /** --------------------------------------------------------------------
        Replaces all sequences of numbers shorter than 10 digits by 0-padded
        numbers that exactly 10 digits in length. Usefull for ordering-by
        using NATURAL ORDER algorithm.
     */
        l_result  varchar2( 32700 );
        l_len     integer;
        l_ix      integer;
        l_end     integer;
    begin
        l_result := P_STR;
        l_len := LENGTH( l_result );
        l_ix := 1;
        while l_len > 0 loop
            l_ix := REGEXP_INSTR( l_result, '[0-9]{1,9}', l_ix, 1, 0 );
            EXIT when l_ix = 0;
            l_end := REGEXP_INSTR( l_result, '[^0-9]|$', l_ix, 1, 0 );
            if ( l_end - l_ix >= 10 ) then
                l_ix := l_end;
            else
                l_result := substr( l_result, 1, l_ix - 1 )
                         || LPAD( SUBSTR( l_result, l_ix, l_end-l_ix ), 10, '0' )
                         || substr( l_result, l_end )
                         ;
                l_ix := l_ix + 10;
            end if;
        end loop;
        return l_result;
    end;
    /
    Et l'utiliser comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    select code
    from bidule
    order by natural_order(code);
    Tu peux essayer de t'en inspirer.
    On ne jouit bien que de ce qu’on partage.

  4. #4
    Membre du Club
    Profil pro
    Développeur informatique
    Inscrit en
    Mai 2008
    Messages
    100
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2008
    Messages : 100
    Points : 57
    Points
    57
    Par défaut
    Merci, mais c'est vrai que j'ai oublié de dire que je suis sous MySQL.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ORDER BY CAST(bdt.NUMERO_TOME AS INT)
    => Crash

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ORDER BY CAST(bdt.NUMERO_TOME AS SIGNED)
    => Tri : HS,1,2,...,10,11

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ORDER BY IFNULL(CAST(bdt.NUMERO_TOME AS INT),bdt.NUMERO_TOME)
    => Crash

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ORDER BY IFNULL(CAST(bdt.NUMERO_TOME AS SIGNED),bdt.NUMERO_TOME)
    => Tri : HS,1,10,...,2,21

    Je regarde du côté de CASE.
    GRULF

  5. #5
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Je ne sais pas si ça fonctionnerait avec d'autres SGBD mais il se trouve que sous MySQL, si tu divises une colonne par elle-même et que celle-ci a une valeur pouvant être traduite par un nombre, l'opération s'effectue ou donne NULL dans le cas contraire.
    '4' / '4' => 1
    'HS 1' / 'HS 1' => NULL

    Donc avec cette requête qui donne une priorité aux divisions non nulles, tu obtiens le bon classement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT bd_id, bd_numero
    FROM bede
    ORDER BY 
        CASE 
            WHEN bd_numero/bd_numero IS NOT NULL THEN 1
            ELSE 2
        END,
        bd_numero
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  6. #6
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Je pense tout de même qu'il serait plus intéressait de trouver comment faire un natural sort avec MySQL (ça doit être possible).

    En effet, autant "4" est avant "HS 1", autant il est après "1 HS".

    Idem pour trier "HS 1", "HS 10" et "HS "2".

    Si vraiment MySQL ne le supporte pas, il faudrait peut-être penser à faire ce tri non pas dans le SGBD mais dans l'outils qui interroge le SGBD, mais niveau performances, ça peut vite devenir moyen, et surtout ça ne résoud pas tout les cas, notamment si tu en as besoin lors de traitements plus complexes en PL/SQL notamment.
    On ne jouit bien que de ce qu’on partage.

  7. #7
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Effectivement, il peut y avoir problème avec l'ordre HS 1, HS 10, HS 2.

    Si tous les HS sont formés de la même manière (par exemple les lettres HS suivies d'un espace puis d'un numéro), alors on peut utiliser les fonctions de chaîne supprimer les caractères et trier les numéros.

    Pas le temps d'étudier ça maintenant mais c'est l'idée.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  8. #8
    Membre du Club
    Profil pro
    Développeur informatique
    Inscrit en
    Mai 2008
    Messages
    100
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2008
    Messages : 100
    Points : 57
    Points
    57
    Par défaut
    Merci pour vos réponses, je regarderai ça lundi.
    Mais je pense que la solution de CinePhil devait me suffire. Les HS sont formés de la même manière, et il ne devrait pas y en avoir plus de 3 ou 4 pour chaque résultat de requête.
    Je teste ça demain et je vous redis si j'arrive à en faire ce que je veux.
    Merci
    GRULF

  9. #9
    Membre expérimenté
    Homme Profil pro
    Ingenieur de recherche - Ecologue
    Inscrit en
    Juin 2003
    Messages
    1 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingenieur de recherche - Ecologue

    Informations forums :
    Inscription : Juin 2003
    Messages : 1 146
    Points : 1 412
    Points
    1 412
    Par défaut
    Une petite remarque (en passant).
    Ne serait il pas judicieux (si c'est possible dans ton contexte, bien sur), d'avoir
    * une colonne "Type" Integer
    * une colonne "HS" analogue boolean

    et une contrainte d'unicité sur ces 2 colonnes.


    Comme cela ton tri serait
    et te donnerait le résultat escompté.

    Mais seulement si tu peux modifier la structure
    Merci d'ajouter un sur les tags qui vous ont aidé

  10. #10
    Membre du Club
    Profil pro
    Développeur informatique
    Inscrit en
    Mai 2008
    Messages
    100
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2008
    Messages : 100
    Points : 57
    Points
    57
    Par défaut
    Effectivement, ça serait plus judicieux, vu que je peux modifier la structure.
    Je vais partir là-dessus. Merci
    GRULF

  11. #11
    Membre expérimenté
    Avatar de islamov2000
    Homme Profil pro
    Ingénieur d'études & developpement en informatique
    Inscrit en
    Septembre 2007
    Messages
    814
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Ingénieur d'études & developpement en informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2007
    Messages : 814
    Points : 1 717
    Points
    1 717
    Billets dans le blog
    6
    Par défaut
    si tu n'as que des données de type 1,2,3...66..366.9999 et HS1,HS2..HS660 ou HS 1,HS 2...HS 654,...
    voici la requête sous ORACLE
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    select 
    * from tab1 t
    order by decode(LENGTH(TRIM(TRANSLATE (champ, ' +-.0123456789',' '))),null,to_number(champ)),
    to_number(substr( champ,3,length(champ)))
    le principe est simple sachant que l'on n'a que des 1,2,3...HS1,HS2,HS3....HS 1,HS 2,HS 3....:
    1/ on fait le premier tri comme suit :
    on teste si le champ est un numérique, généralement dans les autres SGBD on trouve la fonction is_numeric...isnumeric ou ..., puis on le convertit en numérique.
    2/ deuxième tri : on tronque le champ à partir du troisième caractère en prenant la partie numérique, puis on convertit cette dernière en numérique.
    d'avoir Pensé à voter positivement pour ceux qui vous ont aidés et surtout à mettre si le cas.
    ça encourage.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 7
    Dernier message: 13/04/2007, 15h39
  2. Problème de casse sur des varchar
    Par PomPom dans le forum Requêtes
    Réponses: 2
    Dernier message: 20/09/2006, 18h28
  3. [Conception] Requête sur des dates pour stats
    Par vallica dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 30/05/2006, 10h15
  4. taille des varchars pour utf8
    Par myheqa dans le forum Installation
    Réponses: 10
    Dernier message: 21/05/2006, 23h52
  5. "Order by" sur des valeurs spécifiques
    Par damienTrax dans le forum Requêtes
    Réponses: 2
    Dernier message: 23/11/2004, 09h20

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo