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 :

SQL SELECT pour un resultat dénormalisé


Sujet :

Langage SQL

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    254
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 254
    Points : 80
    Points
    80
    Par défaut SQL SELECT pour un resultat dénormalisé
    Bonjour,

    Je suis à la recherche de solution pour un cas suivant:

    Table source contient:
    ID CODE VALEUR
    -- -------
    1 A a1
    2 B b2
    3 A a3
    4 C c4
    1 B b1
    6 D d6
    1 C c1
    2 C c2
    j'ai besoin de faire un select présenter le résultat suivant:

    ID |A |B |C | D
    -- |--- |--- |---|---
    1 |a1 |b1 |c1 |nul
    2 |nul |b2 |c2 |nul
    3 |a3 |nul |nul |nul
    4 |nul |nul |c4 |nul
    6 |nul |nul |nul |d6
    La liste de valeurs dans la colonne "Valeur" n'est pas prédéfinie, peut contenir un nombre variable de valeurs non connues (A, B, C, D, E, F, ...)
    Quelqu'un, aurait-il une idée ?


    Merci
    msomso

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    861
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 861
    Points : 965
    Points
    965
    Par défaut
    Bonjour,

    Il s'agit d'un pivot, la requête devrait ressembler à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    SELECT 
          ID,
          MAX(CASE CODE WHEN 'A' THEN VALEUR ELSE NULL END) AS A,
          MAX(CASE CODE WHEN 'B' THEN VALEUR ELSE NULL END) AS B,
          ...
    FROM Source
    GROUP BY ID
    Comme vos codes ne sont pas connus à l'avance, vous devrez générer votre requête dynamiquement.
    N'oubliez pas de préciser votre SGBD si vous voulez plus d'aide.

    EDIT : je n'avais pas fait attention que votre ID n'est pas unique, il faut donc ajouter un agregat (j'ai utilisé max).
    cf ce sujet récent, notamment la requête proposée par Waldar http://www.developpez.net/forums/d76...-requetes-sql/

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    254
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 254
    Points : 80
    Points
    80
    Par défaut
    Bonjour

    1. Il s'agit de base Oracle.

    2. Je n'ai peut être pas tout compris, mais comment faire marcher cette solution pour un nombre indéfini d'avance de valeurs indéfinies.
    Je m'explique, je peux trouver à titre d'exemple des cas suivants:
    - A, C, D
    - B
    - F, J, M, O, N, W, ...

    Donc, ni le nombre de valeurs ni les valeurs ne sont connus avant la requete.

    merci
    msomso

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    861
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 861
    Points : 965
    Points
    965
    Par défaut
    Vous devez générer votre requête dynamiquement dans une procédure pl/sql à partir du contenu de votre table, comme mentionné dans le lien que je vous ai posté.
    Dans votre cas, vous pouvez essayer comme ça :

    - Récupérer la liste des gestionnaires de votre table
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    CURSOR CurCode IS
    SELECT DISTINCT CODE
    FROM Source
    ORDER BY CODE;
     
    requete VARCHAR2(4000);
    - Construire votre requête dans une variable

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    -- Début de requete
    requete := 'SELECT s.ID';
     
    -- Partie variable de la requete, en bouclant sur les codes
    FOR ligne_cur IN CurCode
    LOOP
         requete := requete || ', MAX(CASE s.CODE WHEN ''' || ligne_cur.code || ''' THEN s.VALEUR ELSE NULL END) AS ' || ligne_cur.code;
    END LOOP;
     
    -- Fin de la requête
    requete := requete || ' FROM Source s GROUP BY s.ID';

  5. #5
    Membre émérite Avatar de pacmann
    Homme Profil pro
    Consulté Oracle
    Inscrit en
    Juin 2004
    Messages
    1 626
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consulté Oracle
    Secteur : Distribution

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 626
    Points : 2 845
    Points
    2 845
    Par défaut
    Salut !

    Si tu n'as pas absolument besoin que ce soient des colonnes, avec des NULL dedans, tu peux tenter un truc à base de récursivité :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    SELECT SYS_CONNECT_BY_PATH(valeur, ';')
    FROM 
     (
     SELECT *, ROW_NUMBER() OVER (PARTITION BY id, ORDER BY code) rk
     FROM source a
     )
    CONNECT BY prior rk = rk -1
      AND prior id = id
    En gardant les meilleurs "level", tu obtiens la concaténation des valeurs.
    Maintenant, ce ne sont que les valeurs qui existent pour cet id.
    Si tu veux remplir avec des NULL, il y a un plan qui va tuer ton Oracle :

    - Tu prends les distincts CODE de ta table, tu attribue un numéro à chacun (genre avec ROW_NUMBER)
    - Tu prends les distincts id de ta table
    - Tu fais le produit cartésien entre les deux
    - Tu fait une jointure externe du résultat avec la table source
    - Et tu appliques la requête ci-dessus sur le résultat.

    Tout ça pour de la présentation... c'est surement mieux de le faire par programmation

    (c'est ma photo)
    Paku, Paku !
    Pour les jeunes incultes : non, je ne suis pas un pokémon...

    Le pacblog : http://pacmann.over-blog.com/

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    254
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 254
    Points : 80
    Points
    80
    Par défaut
    Bonjour

    Snipah : oui, j'ai compris davantage en lisant le lien. Je suis désolée, mais j'ai répondu ... avant de pouvoir lire le lien (j'étais en déplacement).

    Pacmann : merci c'est très intéressant, je dois tester pour ... comprendre.

    msomso

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    254
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 254
    Points : 80
    Points
    80
    Par défaut re pacmann
    Bonjour,
    j'ai essayé de tester.
    Pourrais-tu me dire ce qui ne va pas dans ta requête (j'ai corrigé déjà certaines erreurs):

    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
     
    create table T1 (ID integer, code varchar2(10), valeur varchar2(10));
    insert into T1 values (1,'A', 'a1');
    insert into T1 values (2,'B', 'b2');
    insert into T1 values (3,'A', 'a3');
    insert into T1 values (4,'C', 'c4');
    insert into T1 values (1,'B', 'b1');
    insert into T1 values (6,'D', 'd6');
    insert into T1 values (1,'C', 'c1');
    insert into T1 values (2,'C', 'c2');
    commit;
     
    SELECT SYS_CONNECT_BY_PATH(valeur, ';')
    FROM ( SELECT id, code, valeur, ROW_NUMBER() OVER (PARTITION BY id ORDER BY code) FROM t1 a ) rk
    CONNECT BY prior rk = rk -1
      AND prior id = id;
    Ceci se termine par:
    SQL> SELECT SYS_CONNECT_BY_PATH(valeur, ';')
    2 FROM ( SELECT id, code, valeur, ROW_NUMBER()OVER (PARTITION BY id ORDER BY code) FROM t1 a ) rk
    3 CONNECT BY prior rk = rk -1 AND prior id = id;
    CONNECT BY prior rk = rk -1 AND prior id = id
    *
    ERREUR à la ligne 3 :
    ORA-00904: "RK" : identificateur non valide
    Merci
    msomso

  8. #8
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Vous n'avez pas mis le RK au bon endroit, c'est l'alias de la colonne row_number(), pas de la vue imbriquée.

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    254
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 254
    Points : 80
    Points
    80
    Par défaut
    Bonjour
    en effet, j'ai mal interprété la signification de l'alias.
    Merci beaucoup: ça marche
    msomso

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

Discussions similaires

  1. Print et Select pour afficher resultat pas possible en Trigger
    Par facilus68 dans le forum SQL Procédural
    Réponses: 1
    Dernier message: 16/12/2012, 08h02
  2. Réponses: 8
    Dernier message: 10/10/2007, 13h12
  3. [SQL] Problème pour récupérer le resultats d'une requête
    Par -Neo- dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 14/06/2007, 10h50
  4. faire un count pour chaque resultat du select en mêm temps
    Par djouahra.karim1 dans le forum Bases de données
    Réponses: 11
    Dernier message: 09/05/2005, 15h30
  5. [VB.NET] [SQL] Retour d'un SELECT pour un IF/ELSE
    Par nys_00 dans le forum Windows Forms
    Réponses: 7
    Dernier message: 17/03/2005, 12h50

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