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

Firebird Discussion :

comment ordonner une table sur un champs alphanumerique comme un numérique


Sujet :

Firebird

  1. #1
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    mars 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : mars 2010
    Messages : 852
    Points : 88
    Points
    88
    Par défaut comment ordonner une table sur un champs alphanumerique comme un numérique
    Bonjour à tous,

    dans un précédent post http://www.developpez.net/forums/d15...ant-numerique/ j'ai exposé le problème de la recuperation des valeurs numérique sur un champs alphanumérique et continuons sur le même registre je voudrais trié les enregistrements trouvé dans un ordre numérique.

  2. #2
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique
    Inscrit en
    janvier 2007
    Messages
    13 372
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 65
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2007
    Messages : 13 372
    Points : 36 247
    Points
    36 247
    Billets dans le blog
    54
    Par défaut
    Bonjour, pour les tris il s'agit d'un problème de COLLATION par contre cela dépend aussi du CHARSET utilisé

    pistes de lectures http://www.destructor.de/firebird/charsets.htm,http://sqlpro.developpez.com/cours/s...er/collations/

    cependant je ne suis pas sur qu'il existe un COLLATION 'toute faite' du permettant un genre de tri
    0,1,2,3,....,
    10,11, ...,
    20,21 ...
    puis Alphabétique

    depuis FB 2.1 on peut ajouter des COLLATION a nos bases de données la version 2.5 a encore amélioré le processus
    http://www.firebirdsql.org/refdocs/l...collation.html

    un exemple que j'ai trouvé (en portuguais)
    O Firebird 2.5 permite que collates sejam configuráveis, e uma das opções do collate UNICODE permite que números sejam ordenados por ordem numérica. A listagem 4 mostra a criação do collate UNICODE_NUM com o uso da opção NUMERIC-SORT e a ordenação usando este collate.

    Listagem 4. Ordenação usando a opção NUMERIC-SORT do collate UNICODE.
    tentative de traduction
    [QUOTE]Firebird 2.5 permet que les ordres de tri (collation) soit configurées, une option que UNICODE permet est que les numéros soient triés en ordre numérique ....
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    CREATE COLLATION UNICODE_NUM FOR UTF8 FROM UNICODE 'NUMERIC-SORT=1';
     
    CREATE TABLE DOCUMENTOS2 (
      CODIGO VARCHAR(10) CHARACTER SET UTF8 COLLATE UNICODE_NUM
    );
     
    INSERT INTO DOCUMENTOS2 SELECT * FROM DOCUMENTOS;
     
    -- Resultat: A1, A2, A10, A11, A100, B1, B10
    SELECT CODIGO FROM DOCUMENTOS2 ORDER BY CODIGO;
    à te lire pour connaitre ta solution à partir de ces éléments
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Tokyo, Rio, Sidney) ,D11 (Alexandria)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs Etats : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Ubuntu, Androïd

  3. #3
    Membre expert
    Avatar de Barbibulle
    Profil pro
    Inscrit en
    octobre 2002
    Messages
    2 043
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France

    Informations forums :
    Inscription : octobre 2002
    Messages : 2 043
    Points : 3 328
    Points
    3 328
    Par défaut
    Bonjour,

    La création d'un collation me parait le plus intéressant (et universelle si vous avez d'autres colonnes à traiter de la même manière)

    Cependant, il y a d'autres alternatives

    Si vous souhaitez ne trier que les chaines etapro qui ne contiennent que des chiffres vous pouvez procéder autrement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Select * 
    from produit p
    order by (case when p.etapro similar to '[[:DIGIT:]]{1,}' then cast(p.etapro as integer)
         else null
         end);
    Le problème c'est si votre table est énorme, cette requête va balayer toute votre table et donc risque d'être longue.

    Dans ce cas il faut créer un index "calculé" :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    CREATE INDEX PRODUIT_IDX1 ON PRODUIT COMPUTED BY (case when etapro similar to '[[:DIGIT:]]{1,}' then cast(etapro as integer)
         else null
         end);
    Si vous ne voulez pas créer d'index calculé, une seconde solution consisterai à ajouter une colonne "ETAPRONUM integer" à votre table produit. Cette colonne serait automatiquement alimentée par des triggers avec la valeur numerique, vous pouvez créer un index 'classique' sur cette colonne.

    Enfin pour conclure troisième alternative, vous pouvez également ajouter une colonne calculée
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ETAPRONUM  COMPUTED BY (case when etapro similar to '[[:DIGIT:]]{1,}' then cast(etapro as integer)
         else null
         end)
    On ne peut pas créer directement d'index sur cette colonne il vous faudra créer un index calculé de la même manière.

    la requête
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    select * from produit 
    order by etapronum
    utilisera bien l'index calculé.

  4. #4
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    mars 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : mars 2010
    Messages : 852
    Points : 88
    Points
    88
    Par défaut
    Bonjour et merci pour vos réponses,

    les 2 méthodes peuvent être une solution,cependant la solution de @Barbibulle me parait la plus facile et rapide à utilisée. je vai testé tous ça et je vous tiens au courant.

  5. #5
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    mars 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : mars 2010
    Messages : 852
    Points : 88
    Points
    88
    Par défaut
    rebonjour,

    je crois que j'ai parlé trop vite pour la réponse de @barbibulle, ça exige que la champs "etapro" contienne que des numériques pour un champs crée pour une saisie alphanumérique. Par contre , la méthode de @sergio nécessite de crée une autre table et je ne sais pas si le tri ce fait sur n'importe quelle valeurs, je m'explique. En effet, la table produit est créer pour une entreprise de vente d'articles d'occasion de tout genre alors la codification est anarchique exple:

    PRO DÉSIGNATION
    ---------------------------------------------------
    CHA001 Chaise roulante
    045545 Perceuse électrique
    RTDSSG Calculette
    578 /dg Moteur électrique
    .....
    ....
    -----------------------------------
    et dés fois il ya des articles sans code et là la codification automatique doit être appliquée. donc comment récupérer la plus grande valeur seulement sur les champs numériques de la table?

  6. #6
    Membre expert

    Homme Profil pro
    Consultant spécialité Firebird
    Inscrit en
    mai 2002
    Messages
    2 342
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France

    Informations professionnelles :
    Activité : Consultant spécialité Firebird
    Secteur : Conseil

    Informations forums :
    Inscription : mai 2002
    Messages : 2 342
    Points : 3 701
    Points
    3 701
    Par défaut
    Citation Envoyé par chekkal Voir le message
    Par contre , la méthode de @sergio nécessite de crée une autre table
    non
    juste un ordre de tri que l'on appliquera sur le champ
    Philippe Makowski
    IBPhoenix - Firebird
    Membre de l'April

  7. #7
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique
    Inscrit en
    janvier 2007
    Messages
    13 372
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 65
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2007
    Messages : 13 372
    Points : 36 247
    Points
    36 247
    Billets dans le blog
    54
    Par défaut
    Bonjour,

    Par contre , la méthode de @sergio nécessite de crée une autre table
    cela m'apprendra à ne pas mettre le lien sur la source de l'article brésilien (je croyais l'avoir mis et maintenant je ne le retrouve pas, désolé)
    [Edit] http://asfernandes.blogspot.fr/2014/...bird-25_5.html

    le code que j'avais fourni était un code de démo donc l'auteur utilisait une table existante DOCUMENTOS et faisait différents tests de tri
    d'où la nécessité de tables "dérivées" (pas une seule dans le document car plusieurs tri)

    dans ton cas après avoir créer ta collation
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CREATE COLLATION MONSORT_NUM FOR UTF8 FROM UNICODE 'NUMERIC-SORT=1';
    pour changer ensuite la colonne et en faire un "tri permanent"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    ALTER TABLE PRODUITS ALTER COLUMN PRO TYPE VARCHAR(10) CHARACTER SET MONSORT_NUM
    donc 2 lignes, une fois , c'est pas la mer à boire

    pour en faire un tri "non permanent" et laisser la colonne "intacte" (telle que crée par le concepteur de la BDD) j'ai un doute , peut être via un CAST plus surement via une VIEW
    là je ne trouve pas la réponse
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Tokyo, Rio, Sidney) ,D11 (Alexandria)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs Etats : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Ubuntu, Androïd

  8. #8
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    mars 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : mars 2010
    Messages : 852
    Points : 88
    Points
    88
    Par défaut
    Bonjour,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ALTER TABLE PRODUITS ALTER COLUMN PRO TYPE VARCHAR(10) CHARACTER SET MONSORT_NUM
    là donc on doit modifier le champs de la table "produit", mais c'est pas mon but.

    Par contre pour le CAST, j'ai cru que c’était la solution mais il me signale des erreur "integer overflow"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Select etatpro from produit where ( etapro similar to '[[:DIGIT:]]{1,})
    order by (case when etapro similar to '[[:DIGIT:]]{1,}' then cast(etapro as integer)
         else null
         end);
    ce que je comprend pas c'est comment firebird étudie ce code,en effet je crois qu'avant d'appliquer le "order by" il doit d'abord exécute le filtre "where"?

  9. #9
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique
    Inscrit en
    janvier 2007
    Messages
    13 372
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 65
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2007
    Messages : 13 372
    Points : 36 247
    Points
    36 247
    Billets dans le blog
    54
    Par défaut
    Citation Envoyé par chekkal Voir le message
    et dés fois il ya des articles sans code et là la codification automatique doit être appliquée. donc comment récupérer la plus grande valeur seulement sur les champs numériques de la table?
    rein n'empêche un générateur , sauf qu'il va falloir gérer deux choses :
    1 - les codes non numériques
    2 - la conversion de numérique vers varchar
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Tokyo, Rio, Sidney) ,D11 (Alexandria)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs Etats : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Ubuntu, Androïd

  10. #10
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique
    Inscrit en
    janvier 2007
    Messages
    13 372
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 65
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2007
    Messages : 13 372
    Points : 36 247
    Points
    36 247
    Billets dans le blog
    54
    Par défaut
    Citation Envoyé par chekkal Voir le message
    Bonjour,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ALTER TABLE PRODUITS ALTER COLUMN PRO TYPE VARCHAR(10) CHARACTER SET MONSORT_NUM
    là donc on doit modifier le champs de la table "produit", mais c'est pas mon but.
    il n'est pas "modifié" seul la collation est changée , les alphanumériques restent des alphanumériques (les lettres alphabétiques ne sont pas enlevées)

    Par contre pour le CAST, j'ai cru que c’était la solution mais il me signale des erreur "integer overflow"
    ton code pèche si tu ôtes via le where tout les enregistrements non numériques alors tu n'as pas besoin du case

    enfin quel est le but exact du code ? s'il s'agit de récupérer le dernier champ numérique comme le suggère ta phrase
    des fois il y a des articles sans code et là la codification automatique doit être appliquée.
    et comme le titre du départ le demandait un tri numérique
    alors c'est la solution générateur+trigger qui me semble la plus adaptée. Reste que ma proposition plus haut n'est pas au point
    je viens de tenter de le faire dans une base bidon et
    la partie erreur de conversion est revoir

    [Edit] mon trigger qui fonctionne
    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
    SET TERM ^ ;
    CREATE TRIGGER PRODUITS_BI ACTIVE
    BEFORE INSERT POSITION 0
    AS
    DECLARE VARIABLE tmp DECIMAL(10,0);
    DECLARE VARIABLE tmppro DECIMAL(10,0);
    BEGIN
      IF (NEW.PRO IS NULL) THEN
        NEW.PRO = GEN_ID(GEN_PRODUITS_ID, 1);
      ELSE
      BEGIN
        if (NEW.PRO SIMILAR TO '[1]{1,}') THEN tmppro=CAST(NEW.PRO AS INTEGER);
                                          ELSE tmppro = 0; 
        tmp = GEN_ID(GEN_PRODUITS_ID, 0);
        if (tmp < tmppro) then
          tmp = GEN_ID(GEN_PRODUITS_ID, tmppro-tmp);
      END
    END^
    SET TERM ; ^
    bien sur avec un générateur /sequence crée GEN_PRODUITS_ID auparavant
    sur ma base test , avec le charset indiqué auparavant MONSORT_NUM c'est nickel
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Tokyo, Rio, Sidney) ,D11 (Alexandria)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs Etats : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Ubuntu, Androïd

  11. #11
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique
    Inscrit en
    janvier 2007
    Messages
    13 372
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 65
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2007
    Messages : 13 372
    Points : 36 247
    Points
    36 247
    Billets dans le blog
    54
    Par défaut
    et enfin une réponse simple à la question obtenir le plus grand nombre* dans une colonne alphanumérique, sans passer par generateur + trigger et sans COLLATION**
    * ça se limite quand même à un max de 18 chiffres
    ** et ça ne fait pas le tri (titre du sujet : comment ordonner .....)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Select FIRST 1 CAST(etapro AS DECIMAL(18,0)) from produits where etapro similar to '[[:DIGIT:]]{1,}'
    order by 1 DESC
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Select  CAST(etapro AS DECIMAL(18,0)) from produits where etapro similar to '[[:DIGIT:]]{1,}'
    order by 1 DESC
    ROWS 1
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Tokyo, Rio, Sidney) ,D11 (Alexandria)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs Etats : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Ubuntu, Androïd

  12. #12
    Membre expert
    Avatar de Barbibulle
    Profil pro
    Inscrit en
    octobre 2002
    Messages
    2 043
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France

    Informations forums :
    Inscription : octobre 2002
    Messages : 2 043
    Points : 3 328
    Points
    3 328
    Par défaut
    Citation Envoyé par chekkal Voir le message
    Bonjour,
    Par contre pour le CAST, j'ai cru que c’était la solution mais il me signale des erreur "integer overflow"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Select etatpro from produit where ( etapro similar to '[[:DIGIT:]]{1,})
    order by (case when etapro similar to '[[:DIGIT:]]{1,}' then cast(etapro as integer)
         else null
         end);
    ce que je comprend pas c'est comment firebird étudie ce code,en effet je crois qu'avant d'appliquer le "order by" il doit d'abord exécute le filtre "where"?
    C'est que tout simplement vous avez une valeur d'etapro qui contient que des chiffres mais qui dépasse la capacité d'un integer...

    Un integer ne peut contenir que des valeurs comprises entre -2147483648 et 2147483647

    Il faudrait utiliser un bigint qui peut contenir des valeurs comprises entre -9223372036854775808 et 9223372036854775807

    ou un numeric(18,0) qui en théorie prend des valeurs comprises entre -999999999999999999 et 999999999999999999 mais en pratique peut contenir plus (même plage que le bigint).

    Le select ci dessous vous listera les produits dont etapro ne contient que des chiffres et ayant plus de 10 chiffres (donc qui potentiellement provoque l'erreur overflow
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Select * 
    from produit p
    where p.etapro similar to '[[:DIGIT:]]{1,}'
      and substring (p.etapro from 10 for 1) <> ''

    En conclusion si votre colonne etapro est un varchar de longueur supérieur à 18 positions vous risquez d'avoir cette erreur (même en utilisant le bigint)...

    Conclusion bis => utiliser la méthode de COLLATION proposé par SergioMaster

    Nota : Ma méthode permettait de trier que les etapro contenant des chiffres à condition qu'il n'y ai pas de dépassement de capacité (si vous aviez donné la définition de votre colonne j aurai pu anticipé le problème) les etapro ne contenant pas de chiffre étant quand a eux non trié. D'où l'importance de bien décrire vos problèmes, et aussi votre but final.

  13. #13
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    mars 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : mars 2010
    Messages : 852
    Points : 88
    Points
    88
    Par défaut
    bonjour,

    le code proposé par @sergio
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    select FIRST 1 CAST(etapro AS DECIMAL(18,0)) from produits where etapro similar to '[[:DIGIT:]]{1,}'
    order by 1 DESC
    est efficace, sauf que le champs etatpro est un varchar(20), donc il faut trouvé un moyen de controler la taille du champs exple:'12457898787878797875' déclenche une exception

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

Discussions similaires

  1. peut on filtrer une table sur deux champs
    Par lila23 dans le forum Débuter
    Réponses: 3
    Dernier message: 20/04/2009, 18h48
  2. Réponses: 1
    Dernier message: 09/11/2006, 13h08
  3. [D7],[ADO] : ordonner une table avec des champs référencés
    Par iam dans le forum Bases de données
    Réponses: 3
    Dernier message: 07/11/2006, 22h36
  4. [C# 2.0] Comment créer une table sur un serveur SQL 2000 ?
    Par Filippo dans le forum Accès aux données
    Réponses: 1
    Dernier message: 15/09/2006, 14h30
  5. [ADO.NET]Comment réaliser une relation sur plusieurs champs?
    Par kleomas dans le forum Accès aux données
    Réponses: 3
    Dernier message: 13/03/2006, 13h40

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