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

PHP & Base de données Discussion :

Obtenir un tableau sans utiliser GROUP_CONCAT


Sujet :

PHP & Base de données

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 59
    Points : 54
    Points
    54
    Par défaut Obtenir un tableau sans utiliser GROUP_CONCAT
    Bonjour,

    je suis face à une situation plus que classique : j'ai deux tables A et B associées l'une à l'autre par une table de relation a_has_b .

    Un élément de A est associé à plusieurs lignes dans B.

    Mon objectif est pour une ligne donnée de A, obtenir cette ligne plus l'ensemble des champs `noms` des lignes de B correspondantes concaténés entre eux et séparés par une virgule.

    Ex :

    ----------------------
    | id | b_names |
    ----------------------
    | 10 | toto, tata |
    ----------------------

    Ce problème étant j'imagine très courant, je suppose qu'il doit y avoir un pattern pour le résoudre non ?

    Voilà la manière dont je procède :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    SELECT a.*, d.names as b_names
    FROM a 
    LEFT JOIN (
    SELECT GROUP_CONCAT( name ) AS NAMES, ida 
    FROM (
    SELECT b.name AS name, ahb.a_ida as ida
    FROM a_has_b AS ahb
    LEFT JOIN b ON b.idb = ahb.b_idb
    WHERE a_ida = 10
    ) AS list) AS d on d.ida = a.ida
    WHERE a.ida = 10
    Cela me semble bien compliqué...
    Y-a-til une solution plus élégante ?

  2. #2
    ced
    ced est déconnecté
    Rédacteur/Modérateur

    Avatar de ced
    Homme Profil pro
    Gestion de bases de données techniques
    Inscrit en
    Avril 2002
    Messages
    6 016
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Gestion de bases de données techniques
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Avril 2002
    Messages : 6 016
    Points : 23 705
    Points
    23 705
    Par défaut
    Bonjour,

    Citation Envoyé par dedis Voir le message
    Y-a-til une solution plus élégante ?
    Oui. La solution la plus élégante, et la plus logique, consiste à ne pas utiliser le SQL pour tous ces problèmes de cosmétique des données (le SQL n'est pas fait pour ça), mais à utiliser le langage qui interroge la base pour réaliser ces opérations (PHP par exemple).

    C'est effectivement une question récurrente, à laquelle un tutoriel apporte des réponses très pertinentes : http://sqlpro.developpez.com/cours/sqlaz/erreurs/#L9

    ced
    Rédacteur / Modérateur SGBD et R
    Mes tutoriels et la FAQ MySQL

    ----------------------------------------------------
    Pensez aux balises code et au tag
    Une réponse vous a plu ? N'hésitez pas à y mettre un
    Je ne réponds pas aux questions techniques par message privé, les forums sont là pour ça

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 59
    Points : 54
    Points
    54
    Par défaut
    ok merci beaucoup pour cette réponse précise, je vais prendre le temps de lire la page en entier de manière attentive.

    En fait, j'étais convaincu de bien faire en m'évertuant à écrire des requêtes complexes pour en limiter au maximum le nombre . J'ai cru comprendre que du point de vu de la performance (qui est devenu un critère primordial dans les problématiques de référencement), plus le nombre de requêtes est limité plus le site est réactif.

    Or, la situation que je présente est courante lors de la réalisation de site Web, ne serait-ce par exemple que pour joindre des pages et des catégories. Il me semble que si je voulais ré-écrire mes éléments de 'cosmétiques' en PHP, je serais obligé de casser les sous requêtes en une multitude de petites requêtes indépendantes... J'ai tenté de regarder dans des CMS populaires la manière dont le problème est traité, mais l'utilisation de plus en plus répandue d'ORM rend tout ça assez illisible .

    Existe-t-il un moyen de passer la cosmétique côté PHP en ne faisant qu'une seule requête ?
    Le temps gagné par l'utilisation d'une requête unique est-il réel (ie: si le SGBD met plus temps que PHP à faire la cosmétique... c peut-être simplement contre-productif)?

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 59
    Points : 54
    Points
    54
    Par défaut
    bon désolé de flooder, mais je viens de lire en détail la question sur la cosmétique et les choses sont beaucoup plus claires...

    Comme on le voit, la première requête donne les même résultats que la dernière... Seule la présentation à changée....
    Dans la recherche de la requête complexe donnée dans mon premier post, j'ai en effet d'abord obtenu une première requête simple me donnant un résultat "peu susceptible de plaire aux commerciaux" . Cette requête unique suffira, fin du problème.

    Je suis un peu fatigué là, je la poserais demain et mettrais le sujet en résolu. Merci encore

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 59
    Points : 54
    Points
    54
    Par défaut
    Bon, c fait. Voilà la requête :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT *
    FROM s
         LEFT JOIN (SELECT *
                    FROM  shr
                            LEFT JOIN  r ON r.idr = shr.r_idr
                    ) AS res ON res.ids = s.ids
    WHERE s.ids = 10
    Qui me retourne bien plusieurs lignes qui ne 'plaisent pas aux commerciaux' mais contenant bien toutes les infos requises (en vrai je ne mets pas * mais je liste les colonnes qui m'intéresse).

    Côté PHP :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    foreach($results as $result)
    		{
    		    $row['col1']=$result['col1'];
    		    ...
    		    $row['names'][]=$result['name'];
    		}
    return $row;
    et là, je suis moins sûr... ça marche, mais encore une fois, est-ce élégant ?
    Pour chaque ligne j'écrase les colonnes ayant les mêmes infos, et je place dans un tableau celle qui varie. Comment auriez vous fait ?

  6. #6
    ced
    ced est déconnecté
    Rédacteur/Modérateur

    Avatar de ced
    Homme Profil pro
    Gestion de bases de données techniques
    Inscrit en
    Avril 2002
    Messages
    6 016
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Gestion de bases de données techniques
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Avril 2002
    Messages : 6 016
    Points : 23 705
    Points
    23 705
    Par défaut
    Là, ça devient plus un problème de PHP...

    ced
    Rédacteur / Modérateur SGBD et R
    Mes tutoriels et la FAQ MySQL

    ----------------------------------------------------
    Pensez aux balises code et au tag
    Une réponse vous a plu ? N'hésitez pas à y mettre un
    Je ne réponds pas aux questions techniques par message privé, les forums sont là pour ça

  7. #7
    Expert éminent sénior

    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    7 920
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 7 920
    Points : 10 726
    Points
    10 726
    Par défaut
    avec PDO, tu peux faire ça très facilement (et proprement) grâce au FETCH_GROUP

    J'ai mis un exemple ici :

    exemple :

    +----+-----------+----------+-------+
    | id | firstname | lastname | city |
    +----+-----------+----------+-------+
    | 1 | Jean | Machin | Paris |
    | 2 | Jean | Truc | Nice |
    | 3 | Paul | Bla | Nice |
    +----+-----------+----------+-------+
    on a envie de trier les utilisateur par ville pour avoir une sortie type :

    Tout sélectionner
    Paris
    Jean Machin
    Nice
    Jean Truc
    Paul Bla

    plusieurs solutions :


    Faire une requête DISTINCT sur les villes, et a chaque tour de boucle allé chercher les personnes qui correspondes
    Créer un array temporaire et a chaque tour de boucle ajouter la personne ($tmp[$user['city']][] = $user) , et reboucler ensuite pour créer son tableau
    A chaque tour de boucle vérifier via un buffer si la ville a été mise et afficher les personnes, sinon afficher ville


    la solution PDO :

    Grâce au fetchAll et son option PDO::FETCH_GROUP, on a en sortie directement un array formateé, avec en clé la catégorie et en valeur les entrées correspondantes
    (par contre attention contraiement a PDO::FETCH_COLUMN, on ne choisie pas qui est la catégorie, ca sera uniquement la première colonne)

    exemple de code :


    Code php : 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
    try
    {
        $pdo = new PDO('mysql:host=localhost;dbname=test', 'root');
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
    }
    catch (Exception $e)
    {
        exit($e->getMessage());
    }
     
    $query = $pdo->query("SELECT u.city, u.id, u.firstname, u.lastname FROM test_user u");
     
    if($query)
    {
        $result = $query->fetchAll(PDO::FETCH_ASSOC | PDO::FETCH_GROUP);
        print_r($result);
    }

    en sortie

    Tout sélectionner
    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
    Array
    (
        [Paris] => Array
            (
                [0] => Array
                    (
                        [id] => 1
                        [firstname] => Jean
                        [lastname] => Machin
                    )
     
            )
     
        [Nice] => Array
            (
                [0] => Array
                    (
                        [id] => 2
                        [firstname] => Jean
                        [lastname] => Truc
                    )
     
                [1] => Array
                    (
                        [id] => 3
                        [firstname] => Paul
                        [lastname] => Bla
                    )
     
            )
     
    )
    tout simplement

    Si on veux que la catégorie sois un autre champs il suffis de le mettre en premier (le prénom par exemple)
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT u.firstname, u.id, u.lastname, u.city FROM test_user u
    Tout sélectionner
    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
    Array
    (
        [Jean] => Array
            (
                [0] => Array
                    (
                        [id] => 1
                        [lastname] => Machin
                        [city] => Paris
                    )
     
                [1] => Array
                    (
                        [id] => 2
                        [lastname] => Truc
                        [city] => Nice
                    )
     
            )
     
        [Paul] => Array
            (
                [0] => Array
                    (
                        [id] => 3
                        [lastname] => Bla
                        [city] => Nice
                    )
     
            )
     
    )

    et on peux bien sur doubler les valeurs pour avoir des entrées complètes, ce qui sera d'ailleurs plus simple, au niveau portabilité et pour différentes sorties

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT u.city, u.id, u.firstname, u.lastname, u.city FROM test_user u
    -- ou version raccourcis
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT u.city, u.* FROM test_user u
    Tout sélectionner
    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
    Array
    (
        [Paris] => Array
            (
                [0] => Array
                    (
                        [id] => 1
                        [firstname] => Jean
                        [lastname] => Machin
                        [city] => Paris
                    )
     
            )
     
        [Nice] => Array
            (
                [0] => Array
                    (
                        [id] => 2
                        [firstname] => Jean
                        [lastname] => Truc
                        [city] => Nice
                    )
     
                [1] => Array
                    (
                        [id] => 3
                        [firstname] => Paul
                        [lastname] => Bla
                        [city] => Nice
                    )
     
            )
     
    )

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 59
    Points : 54
    Points
    54
    Par défaut
    Citation Envoyé par stealth35 Voir le message
    avec PDO, tu peux faire ça très facilement (et proprement) grâce au FETCH_GROUP

    J'ai mis un exemple ici :

    exemple :

    +----+-----------+----------+-------+
    | id | firstname | lastname | city |
    +----+-----------+----------+-------+
    | 1 | Jean | Machin | Paris |
    | 2 | Jean | Truc | Nice |
    | 3 | Paul | Bla | Nice |
    +----+-----------+----------+-------+
    on a envie de trier les utilisateur par ville pour avoir une sortie type :

    Tout sélectionner
    Paris
    Jean Machin
    Nice
    Jean Truc
    Paul Bla

    plusieurs solutions :


    Faire une requête DISTINCT sur les villes, et a chaque tour de boucle allé chercher les personnes qui correspondes
    Créer un array temporaire et a chaque tour de boucle ajouter la personne ($tmp[$user['city']][] = $user) , et reboucler ensuite pour créer son tableau
    A chaque tour de boucle vérifier via un buffer si la ville a été mise et afficher les personnes, sinon afficher ville


    la solution PDO :

    Grâce au fetchAll et son option PDO::FETCH_GROUP, on a en sortie directement un array formateé, avec en clé la catégorie et en valeur les entrées correspondantes
    (par contre attention contraiement a PDO::FETCH_COLUMN, on ne choisie pas qui est la catégorie, ca sera uniquement la première colonne)

    exemple de code :


    Code php : 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
    try
    {
        $pdo = new PDO('mysql:host=localhost;dbname=test', 'root');
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
    }
    catch (Exception $e)
    {
        exit($e->getMessage());
    }
     
    $query = $pdo->query("SELECT u.city, u.id, u.firstname, u.lastname FROM test_user u");
     
    if($query)
    {
        $result = $query->fetchAll(PDO::FETCH_ASSOC | PDO::FETCH_GROUP);
        print_r($result);
    }

    en sortie

    Tout sélectionner
    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
    Array
    (
        [Paris] => Array
            (
                [0] => Array
                    (
                        [id] => 1
                        [firstname] => Jean
                        [lastname] => Machin
                    )
     
            )
     
        [Nice] => Array
            (
                [0] => Array
                    (
                        [id] => 2
                        [firstname] => Jean
                        [lastname] => Truc
                    )
     
                [1] => Array
                    (
                        [id] => 3
                        [firstname] => Paul
                        [lastname] => Bla
                    )
     
            )
     
    )
    tout simplement

    Si on veux que la catégorie sois un autre champs il suffis de le mettre en premier (le prénom par exemple)
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT u.firstname, u.id, u.lastname, u.city FROM test_user u
    Tout sélectionner
    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
    Array
    (
        [Jean] => Array
            (
                [0] => Array
                    (
                        [id] => 1
                        [lastname] => Machin
                        [city] => Paris
                    )
     
                [1] => Array
                    (
                        [id] => 2
                        [lastname] => Truc
                        [city] => Nice
                    )
     
            )
     
        [Paul] => Array
            (
                [0] => Array
                    (
                        [id] => 3
                        [lastname] => Bla
                        [city] => Nice
                    )
     
            )
     
    )

    et on peux bien sur doubler les valeurs pour avoir des entrées complètes, ce qui sera d'ailleurs plus simple, au niveau portabilité et pour différentes sorties

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT u.city, u.id, u.firstname, u.lastname, u.city FROM test_user u
    -- ou version raccourcis
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT u.city, u.* FROM test_user u
    Tout sélectionner
    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
    Array
    (
        [Paris] => Array
            (
                [0] => Array
                    (
                        [id] => 1
                        [firstname] => Jean
                        [lastname] => Machin
                        [city] => Paris
                    )
     
            )
     
        [Nice] => Array
            (
                [0] => Array
                    (
                        [id] => 2
                        [firstname] => Jean
                        [lastname] => Truc
                        [city] => Nice
                    )
     
                [1] => Array
                    (
                        [id] => 3
                        [firstname] => Paul
                        [lastname] => Bla
                        [city] => Nice
                    )
     
            )
     
    )
    pour tout dire je fais ça dans Zend avec zend_db_table sur PDO. Mais ce qui m'intéresse c la tête des requêtes générées et savoir si c 'propre'. Visiblement ça ne l'était pas.

    Pour des problématiques aussi basiques que celles-là, j'aimerais savoir quelles sont les bonnes pratiques.

  9. #9
    Expert éminent sénior

    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    7 920
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 7 920
    Points : 10 726
    Points
    10 726
    Par défaut
    Citation Envoyé par dedis Voir le message
    pour tout dire je fais ça dans Zend avec zend_db_table sur PDO. Mais ce qui m'intéresse c la tête des requêtes générées et savoir si c 'propre'. Visiblement ça ne l'était pas.

    Pour des problématiques aussi basiques que celles-là, j'aimerais savoir quelles sont les bonnes pratiques.
    non c'est pas une bonne pratique, une jointure suffis

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 59
    Points : 54
    Points
    54
    Par défaut
    Citation Envoyé par stealth35 Voir le message
    non c'est pas une bonne pratique, une jointure suffis
    Qu'est-ce qui n'est pas une bonne pratique ? Une jointure suffit pour quoi ?

  11. #11
    Expert éminent sénior

    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    7 920
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 7 920
    Points : 10 726
    Points
    10 726
    Par défaut
    Citation Envoyé par dedis Voir le message
    Qu'est-ce qui n'est pas une bonne pratique ? Une jointure suffit pour quoi ?
    de faire un groupe concat

  12. #12
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 59
    Points : 54
    Points
    54
    Par défaut
    Citation Envoyé par stealth35 Voir le message
    de faire un groupe concat
    lol. ok désolé.
    En fait, ce problème là est résolu puisque ced m'a expliqué que la cosmétique n'avait pas sa place côté SQL (et j'imagine donc que FETCH_GROUP de PDO rentre dans ce cadre).

    J'ai donc fait une nouvelle requête SQL, la plus simple que possible, et passé la cosmétique côté PHP avec :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    foreach($results as $result)
    		{
    		    $row['col1']=$result['col1'];
    		    ...
    		    $row['names'][]=$result['name'];
    		}
    return $row;
    Ce qui marche sans problème mais me paraît toujours un peu crado (l'écrasement des données notamment).

    Encore une fois, comme il s'agit d'un problème très basique et très récurent, ce que j'aimerais savoir c'est quelle est la bonne pratique pour ce problème.

    Il doit bien y avoir une solution type ultra-propre recommandées et utilisée par tous non ? Un peu comme pour les pattern en POO ?

  13. #13
    Expert éminent sénior

    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    7 920
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 7 920
    Points : 10 726
    Points
    10 726
    Par défaut
    euh oui avec le FETCH_GROUP...

Discussions similaires

  1. Réponses: 7
    Dernier message: 17/10/2013, 22h54
  2. Réponses: 3
    Dernier message: 24/04/2012, 14h25
  3. Réponses: 2
    Dernier message: 05/03/2012, 16h31
  4. Decimal -> Binaire (sans utiliser de tableau)
    Par Sandro Munda dans le forum C
    Réponses: 3
    Dernier message: 14/10/2006, 18h09
  5. conversion binaire-décimal sans utiliser le tableau
    Par ahmed doua dans le forum Algorithmes et structures de données
    Réponses: 13
    Dernier message: 13/03/2006, 10h54

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