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 - requête GROUP BY avec une liste provenant d'une colonne


Sujet :

Langage SQL

  1. #1
    Membre confirmé
    Homme Profil pro
    étudiant
    Inscrit en
    Juin 2020
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2020
    Messages : 77
    Par défaut SQL - requête GROUP BY avec une liste provenant d'une colonne
    Bonjour,

    Je suis en train de m'arracher les cheveux sur une requête SQL.

    C'est un sujet de patients dans un hopital. Le but est de savoir la liste des repas qu'ils ont choisi (table choix)
    Ils peuvent choisir des repas mais l'hopital peut ne pas leur donner le repas souhaité (table regimerepas).

    Dans la table choix il y a deux colonnes qui représentent des booléens : medical (si le repas est une nécessité médicale) et optionnel si c'est un souhait du patient (ne pas manger de viande par exemple).

    Pour cette requête je dois afficher pour chaque patient (en plus de leur nom et prénom), la liste des repas qu'ils ont choisi en plus de l'option obligatoire ou souhait.

    Ci-dessous les tables :


    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
     
    regime (id, nom)
    id : clé primaire
     
    patient (id, nom, prenom, ...)
    id : clé primaire
     
    choix (idpatient, idregime, optionnel, medical)
    idpatient, idregime : clé primaire
    idpatient : clé étrangère en réf. à id de patient
    idregime : clé étrangère en réf. à id de regime
     
    repas(dateheure, idpatient)
    dateheure, idpatient : clé primaire
    idpatient : clé étrangère en réf. à id de patient
     
    regimerepas(dateheure, idpatient, idregime)
    dateheure, idpatient, idregime: clé primaire
    dateheure, idpatient : clé étrangère en réf. à (dateheure, idpatient) de repas
    idregime : clé étrangère en réf. à id de regime
    J'ai commencé à écrire la requête suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT p.idpatient AS “id”, p.nom AS “nom”, p.prenom AS “prenom”
    FROM choix AS c
    INNER JOIN regime AS r
    ON r.id = c.idregime
    INNER JOIN patient AS p
    ON c.idpatient = p.id
    GROUP BY p.idpatient, p.nom, p.prenom
    ORDER BY p.nom, p.prenom
    Le problème avec cette requête c'est que je ne sais pas comment je pourrais faire apparaitre la liste des repas choisis.
    Normalement si j'utilise un GROUP BY les champs du SELECT devraient aussi se trouver dans le GROUP BY.
    Peut-être que le SELECT je pourrais le transformer en écrivant:

    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
    SELECT id, nom, prenom, repas, …
    FROM (
    	SELECT p.idpatient AS “id”, p.nom AS “nom”, p.prenom AS “prenom”, 
                    (SELECT idpersonnel, nom AS “Liste repas“)
                    FROM regime AS r
                    INNER JOIN choix AS c
                    ON r.id = c.idregime
                    GROUP BY idpersonnel, r.nom)
             FROM choix AS c
             INNER JOIN regime AS r
             ON r.id = c.idregime
             INNER JOIN patient AS p
             ON c.idpatient = p.id
             GROUP BY p.idpatient, p.nom, p.prenom),
    GROUP BY id, nom, prenom
    ORDER BY nom, prenom
    Sinon est-ce que je devrais seulement utiliser des jointures mais dans ce cas comment filtrer par patient ?
    Désolé mais là je suis perdu.

    Merci par avance pour votre aide.

    Cordialement
    Mathieu

  2. #2
    Expert confirmé
    Homme Profil pro
    Responsable Données
    Inscrit en
    Janvier 2009
    Messages
    5 408
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Données

    Informations forums :
    Inscription : Janvier 2009
    Messages : 5 408
    Par défaut
    Bonjour,
    Est-ce que tu peux nous donner un jeu de test et le résultat attendu ?

    En attendant je note que tu utilises un GROUP BY dans ta requête, mais je ne vois aucune agrégation (SUM, AVG...).

    Tatayo.

  3. #3
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 595
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 595
    Billets dans le blog
    10
    Par défaut
    A moins que j'ai loupé un truc, ça me semble tout simple, quelque chose comme ceci (à tester, j'ai pu faire des fautes de frappe) :

    Code SQL : 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
    select PA.nom
         , PA.prenom
         , case when CH.optionnel = 1 then 'OPT'
                                      else 'MED'
           end as Type
         , RP.dateheure
         , RG.nom
    from patient as PA
    inner join choix  as CH
       on CH.idpatient = PA.id
    inner join regime as RG
       on RG.id = ch.idregime
    left outer join repas as RP
       on RP.idpatient = PA.id 
      and RP.dateheure between @datedeb and @datefin
    left outer join regimerepas as RR
       on RR.dateheure=RP.dateheure
      and RR.idpatient=PA.id
      and RR.idregime=RG.id
    order by PA.nom
           , PA.prenom
           , RP.dateheure

  4. #4
    Membre confirmé
    Homme Profil pro
    étudiant
    Inscrit en
    Juin 2020
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2020
    Messages : 77
    Par défaut
    Bonjour,

    Merci beaucoup pour vos retours.

    Est-ce que tu peux nous donner un jeu de test et le résultat attendu ?
    Je ne peux pas parce que l'exercice doit se faire sur papier.
    Nous n'avons aucune base de données pour tester les requêtes de l'exercice.

    Désolé escartefige je me suis mal expliqué dans l'attendu de la requête.

    Pour préparer les repas du lendemain, il est nécessaire de connaître, pour chaque patient (id, nom, prénom), la liste des régimes (nom) avec, pour chacun d'eux, la mention "médical", "confort" ou "optionnel. Les informations du patient n'apparaîtront qu'une seule fois, suivie de la liste des régimes.

    • 'optionnel' permet de savoir, dans le cas d'un choix de régime dit "confort", si le choix est optionnel ;
    • 'medical' permet de savoir si le régime est imposé à ce patient pour des raisons médicales.

      Par défaut, ces 2 champs sont à false.Un tuple de la table choix ne peut pas être à la fois optionnel et médical.
    Dans l'exercice je ne suis pas trop certain de comprendre ce qu'ils attendent entre confort et optionnel. J'ai l'impression que confort c'est quand la colonne optionnel est à true.

    Du coup pour la requête que vous avez proposé escartefigue j'ai dû avec ma mauvaise explication vous induire en erreur.

    Désolé.

    Du coup je suis parti avec un GROUP BY parce que je voulais que les informations du patient n'apparaissent qu'une fois.
    Sinon je cherchais à faire des jointures et à obtenir dans un SELECT imbriqué la liste de tous les régimes pour chaque patient.

    Cordialement

    Mathieu

  5. #5
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 595
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 595
    Billets dans le blog
    10
    Par défaut
    Vu les tables, le lien entre patient et régime se fait grâce à la table "choix", ce qui ne permet qu'une seul régime par patient (ce choix n'étant pas décliné par date)
    Du coup la requête que j'ai proposée correspond a priori au besoin, pour un patient, on a le régime et la liste des dates de repas.
    Dans mon exemple, j'ai choisi de borner sur un intervalle de dates fourni en paramètres.
    J'ai choisi un CASE WHEN ... END pour traduire les booléens du type de régime en une valeur plus facile à comprendre : OPT pour optionnel et MED pour médical.

    Citation Envoyé par __mathieu__
    Du coup je suis parti avec un GROUP BY parce que je voulais que les informations du patient n'apparaissent qu'une fois.
    Puisqu'un patient peut prendre plusieurs repas, il y aura potentiellement plusieurs fois les mêmes informations du patient et c'est tout à fait normal.
    La clause GROUP BY sert à calculer des agrégats tels que la moyenne, la somme, le nombre etc. Comme vous ne calculez pas d'agrégat, il ne faut pas utiliser GROUP BY.

  6. #6
    Membre confirmé
    Homme Profil pro
    étudiant
    Inscrit en
    Juin 2020
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2020
    Messages : 77
    Par défaut
    Bonjour,

    Merci pour votre retour.
    Mais dans ce cas est-ce que l'on n'aura qu'une seule fois les informations liées au patient (nom, prénom, etc).

    Merci par avance

    Cordialement

    Mathieu

  7. #7
    Membre confirmé
    Homme Profil pro
    étudiant
    Inscrit en
    Juin 2020
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2020
    Messages : 77
    Par défaut
    re Bonjour,

    Est-ce que l'on ne pourrait pas mettre DISTINCT dans le SELECT au niveau de l'ID, NOM et PRENOM du PATIENT ?

    Merci par avance

    Cordialement

    Mathieu

  8. #8
    Membre confirmé
    Homme Profil pro
    étudiant
    Inscrit en
    Juin 2020
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2020
    Messages : 77
    Par défaut
    re Bonjour,

    J'ai essayé de reprendre la requête.
    J'ai enlevé la jointure externe de patient vers repas car on a via l'association regimerepas déjà la clé étrangère dateHeure.

    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
     
    SELECT DISTINCT PA.id AS “id”, 
                   DISTINCT PA.nom AS “nom”, 
                   DISTINCT prenom, 
                   IF(CH.optionnel = 1 ,'OPT', 'MED'),
                     RG.nom,
    FROM patient AS PA
    INNER JOIN choix AS CH
    ON CH.idpatient = PA.id
    INNER JOIN regime AS RG
    ON RG.id = CH.idregime
    LEFT OUTER JOIN regimerepas AS RR
    ON RG.id = RR.idregime
    WHERE RR.dateheure IN(
    	SELECT GETDATE() + 1)
    ORDER BY nom, prenom
    Cordialement

    Mathieu

Discussions similaires

  1. Réponses: 7
    Dernier message: 05/05/2010, 18h48
  2. [SQL] Effacer des membres avec une colonne ayant pour valeur un numéro
    Par mecmec dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 20/01/2008, 07h55
  3. Access sql : puis-je faire çà avec une requête ?
    Par kikidrome dans le forum Langage SQL
    Réponses: 10
    Dernier message: 15/11/2006, 08h20
  4. [SQL] Problème de résultat avec une requête
    Par raptorman dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 04/01/2006, 17h16
  5. [ORACLE][SQL] procedure sous delphi avec une requete SQL
    Par nivet dans le forum Bases de données
    Réponses: 2
    Dernier message: 17/11/2004, 13h43

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