Partage
  • Partager sur Facebook
  • Partager sur Twitter

Grouper des données en SQL

Sujet résolu
    18 octobre 2018 à 9:50:48

    Bonjour à tous,

    Je me prends la tête avec ça depuis hier et j'en peux plus, j'ai vraiment besoin d'aide, ne serait-ce que pour avoir une piste et me débloquer. 

    Voilà ce que je souhaiterais faire dans les grandes lignes, un tableau de statistiques permettant de savoir, selon la région, le nombre de RDV qui ont été demandés il y a 2 mois maximum, et à côté ceux qui auront dépassé les 2 mois dans 20 jours et moins (s'ils ont été demandés depuis plus de mois ils deviennent urgents). 

    Pour récupérer les RDV déclenchés dans les 2 mois précédents, je fais un regroupement avec GROUP BY, ce qui fonctionne parfaitement et me donne un tableau avec les données que je veux pour cela!

    select z.nom_region as regions, COUNT(z.nom_region) AS nombre_rdv_a_realiser FROM cc c INNER JOIN cc_utilisateurs u ON c.id_utilisateur = u.id INNER JOIN 
    cc_numeros n ON c.id_numero = n.id INNER JOIN cc_commandes x ON c.id_commande = x.id LEFT OUTER JOIN cc_rdv r 
    ON r.id_cc = c.id LEFT OUTER JOIN cc_audits a ON a.cc_id = c.id LEFT OUTER JOIN departement d ON 
    SUBSTRING(code_postal, 1, 2) = d.code LEFT OUTER JOIN region z ON d.id_region = z.id_region WHERE c.etat = 1 
    AND c.supprime = 0 AND x.supprime = 0 AND c.cc_odm IS NOT NULL AND c.cc_odm = 1 AND cc_odm_habitaplus_cache = 0 
    AND u.id > 0 AND (( a.statut_audit IS NULL OR a.statut_audit <> 3) AND (r.date_rdv = '' OR r.date_rdv IS NULL) 
    AND (c.date_ord is NOT NULL AND sysdate() < ADDDATE(c.date_ord, interval 2 month)) AND 
    (r.non_realisable = 0 OR r.non_realisable IS NULL) AND date_rdv_valide IS NULL) AND c.id not in (select id_cc from cc_rdv_historique) 
    GROUP BY z.nom_region

    Et le tableau

    Mais en plus de cela, comme dit précédemment, je n'arrive pas à trouver comment ajouter la colonne permettant de donner le nombre de RDV urgents. J'y suis arrivé indépendamment de la requête précédente, en changeant simplement les valeurs des dates qui permettent de ne garder que les RDV qui ont été demandés entre il y a 40 jours et il y a 2 mois, de cette manière:

    select z.nom_region as regions, COUNT(z.nom_region) AS nombre_rdv_urgents FROM cc c INNER JOIN cc_utilisateurs u ON c.id_utilisateur = u.id INNER JOIN 
    cc_numeros n ON c.id_numero = n.id INNER JOIN cc_commandes x ON c.id_commande = x.id LEFT OUTER JOIN cc_rdv r 
    ON r.id_cc = c.id LEFT OUTER JOIN cc_audits a ON a.cc_id = c.id LEFT OUTER JOIN departement d ON 
    SUBSTRING(code_postal, 1, 2) = d.code LEFT OUTER JOIN region z ON d.id_region = z.id_region WHERE c.etat = 1 
    AND c.supprime = 0 AND x.supprime = 0 AND c.cc_odm IS NOT NULL AND c.cc_odm = 1 AND cc_odm_habitaplus_cache = 0 
    AND u.id > 0 AND (( a.statut_audit IS NULL OR a.statut_audit <> 3) AND (r.date_rdv = '' OR r.date_rdv IS NULL) 
    AND (c.date_ord is NOT NULL AND SYSDATE() BETWEEN ADDDATE(c.date_ord, interval 40 day) AND ADDDATE(c.date_ord, interval 60 day)) AND 
    (r.non_realisable = 0 OR r.non_realisable IS NULL) AND date_rdv_valide IS NULL) AND c.id not in (select id_cc from cc_rdv_historique)
    GROUP BY z.nom_region

    Les lignes ayant changées étant celles-ci:

    Pour la première requête:

    c.date_ord is NOT NULL AND sysdate() < ADDDATE(c.date_ord, interval 2 month)

    Et pour la seconde:

    c.date_ord is NOT NULL AND SYSDATE() BETWEEN ADDDATE(c.date_ord, interval 40 day) AND ADDDATE(c.date_ord, interval 60 day)

    Et là où je bloque c'est pour faire les deux requêtes à la fois, afin de ne sortir qu'un seul et même tableau, comprenant la région, le nombre de RDV à réaliser, et le nombre de RDV urgents. En gros j'aimerais avoir le tableau suivant:





    Je coince vraiment, et votre aide me serait précieuse, j'espère vraiment pouvoir enfin avancer, 

    Merci d'avance

    EDIT: Je me rends compte d'un problème, mais je ne sais pas comment le résoudre, il se peut que dans certaines régions il n'y ai pas de RDV urgent du tout, ce qui fait qu'au final je me retrouve avec deux tableaux avec un nombre de lignes différentes, ce qui fait que ça ne marche pas, mais je ne sais pas comment palier à ce problème...

    -
    Edité par QuentinSchifferle 18 octobre 2018 à 10:38:34

    • Partager sur Facebook
    • Partager sur Twitter
      18 octobre 2018 à 11:08:07

      Bonjour,

      Le plus simple serait de partir de la liste des régions dans ta requête principale, et de faire deux jointures externes sur deux sous-requêtes, une pour les RDV sous 2 mois, et une pour les autres. La structure serait :

      SELECT
      	z.nom_region as regions,
      	COALESCE( R1.nombre, 0 ) AS a_realiser,
      	COALESCE( R2.nombre, 0 ) AS en_retard
      FROM
      	region z
      		INNER JOIN departement d
      			ON d.id_region = z.id_region
      		LEFT JOIN (
      				SELECT SUBSTRING(code_postal, 1, 2) AS code, COUNT(*) AS nombre
      				FROM ...
      				WHERE ...
      				GROUP BY SUBSTRING(code_postal, 1, 2)
      			) R1
      			ON R1.code = d.code
      		LEFT JOIN (
      				SELECT SUBSTRING(code_postal, 1, 2) AS code, COUNT(*) AS nombre
      				FROM ...
      				WHERE ...
      				GROUP BY SUBSTRING(code_postal, 1, 2)
      			) R2
      			ON R2.code = d.code

      Tu pourrais même créer une vue pour chaque sous-requêtes afin de simplifier la syntaxe ...

      -
      Edité par Benzouye 18 octobre 2018 à 11:08:34

      • Partager sur Facebook
      • Partager sur Twitter
      Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
        18 octobre 2018 à 11:12:28

        Tu peux indenter ta requête, elle est complètement illisible, il serait préférable de le faire en deux requête, ce n'est pas à ton SGBD de faire de la mise en page.

        Sinon, si tu n'a pas le choix, tu peux éssayer un truc du genre:

        SELECT z.nom_region AS regions,
               SUM( sysdate() < ADDDATE(c.date_ord, interval 2 MONTH) ) AS nombre_rdv_a_realiser, 
        	   SUM(SYSDATE() BETWEEN ADDDATE(c.date_ord, interval 40 day) AND ADDDATE(c.date_ord, interval 60 day))AS nombre_rdv_urgents
        FROM cc c
        INNER JOIN cc_utilisateurs u ON c.id_utilisateur = u.id
        INNER JOIN cc_numeros n ON c.id_numero = n.id
        INNER JOIN cc_commandes x ON c.id_commande = x.id
        LEFT OUTER JOIN cc_rdv r ON r.id_cc = c.id
        LEFT OUTER JOIN cc_audits a ON a.cc_id = c.id
        LEFT OUTER JOIN departement d ON SUBSTRING(code_postal, 1, 2) = d.code
        LEFT OUTER JOIN region z ON d.id_region = z.id_region
        WHERE c.etat = 1
          AND c.supprime = 0
          AND x.supprime = 0
          AND c.cc_odm IS NOT NULL
          AND c.cc_odm = 1
          AND cc_odm_habitaplus_cache = 0
          AND u.id > 0
          AND ((a.statut_audit IS NULL
                OR a.statut_audit <> 3)
               AND (r.date_rdv = ''
                    OR r.date_rdv IS NULL)
               AND (c.date_ord IS NOT NULL
                    
        			AND sysdate() <= ADDDATE(c.date_ord, interval 60 day)
        			)
               AND (r.non_realisable = 0
                    OR r.non_realisable IS NULL)
               AND date_rdv_valide IS NULL)
          AND c.id NOT IN
            (SELECT id_cc
             FROM cc_rdv_historique)
        GROUP BY z.nom_region



        • Partager sur Facebook
        • Partager sur Twitter
          18 octobre 2018 à 11:45:52

          MAGNIFIQUE!! Tu ne peux même pas imaginer à quel point je te remercie, ça fonctionne enfin!! Je prenais le problème sous le mauvais angle, il me fallait juste changer ma base de départ, et en prenant ta structure et en la remodelant un peu, ça fonctionne parfaitement!! C'est génail! :D Merci beaucoup!!

          Voilà mon code, si un jour quelqu'un est bloqué de la même façon:

          SELECT DISTINCT(z.nom_region) as regions, COALESCE(a1.nombre, 0) AS a_realiser, COALESCE(a2.nombre, 0) AS dont_urgent from region z 
          
          INNER JOIN departement d ON d.id_region = z.id_region 
          
          LEFT JOIN 
          (SELECT z.nom_region AS code, COUNT(*) AS nombre FROM cc c INNER JOIN cc_utilisateurs u ON c.id_utilisateur = u.id INNER JOIN cc_numeros n ON c.id_numero = n.id INNER JOIN cc_commandes x ON c.id_commande = x.id 
          LEFT OUTER JOIN cc_rdv r ON r.id_cc = c.id LEFT OUTER JOIN cc_audits a ON a.cc_id = c.id 
          LEFT OUTER JOIN departement d ON SUBSTRING(code_postal, 1, 2) = d.code 
          LEFT OUTER JOIN region z ON d.id_region = z.id_region 
          
          WHERE c.etat = 1 AND c.supprime = 0 AND x.supprime = 0 AND c.cc_odm IS NOT NULL AND c.cc_odm = 1 AND cc_odm_habitaplus_cache = 0 AND u.id > 0 AND (( a.statut_audit IS NULL OR a.statut_audit <> 3) 
          AND (r.date_rdv = '' OR r.date_rdv IS NULL) AND (c.date_ord is NOT NULL AND sysdate() < ADDDATE(c.date_ord, interval 2 month)) AND (r.non_realisable = 0 OR r.non_realisable IS NULL) AND date_rdv_valide IS NULL) AND c.id not in (select id_cc from cc_rdv_historique) 
          GROUP BY z.nom_region) a1 ON a1.code = z.nom_region
          
          
          LEFT JOIN (SELECT z.nom_region AS code, COUNT(*) AS nombre 
          
          FROM cc c 
          
          INNER JOIN cc_utilisateurs u ON c.id_utilisateur = u.id 
          
          INNER JOIN cc_numeros n ON c.id_numero = n.id 
          INNER JOIN cc_commandes x ON c.id_commande = x.id 
          LEFT OUTER JOIN cc_rdv r ON r.id_cc = c.id 
          LEFT OUTER JOIN cc_audits a ON a.cc_id = c.id 
          LEFT OUTER JOIN departement d ON SUBSTRING(code_postal, 1, 2) = d.code 
          LEFT OUTER JOIN region z ON d.id_region = z.id_region 
          
          WHERE c.etat = 1 AND c.supprime = 0 AND x.supprime = 0 AND c.cc_odm IS NOT NULL AND c.cc_odm = 1 AND cc_odm_habitaplus_cache = 0 AND u.id > 0 AND (( a.statut_audit IS NULL OR a.statut_audit <> 3) 
          AND (r.date_rdv = '' OR r.date_rdv IS NULL) AND (c.date_ord is NOT NULL AND SYSDATE() BETWEEN ADDDATE(c.date_ord, interval 40 day) AND ADDDATE(c.date_ord, interval 60 day)) AND (r.non_realisable = 0 OR r.non_realisable IS NULL) AND date_rdv_valide IS NULL) AND c.id not in (select id_cc from cc_rdv_historique) 
          GROUP BY z.nom_region) a2 on a2.code = z.nom_region



          EDIT: Je viens de voir ton message Florent m, et effectivement je n'avais pas le choix, sinon j'aurais fait du traîtement avec PHP pour me simplifier la tâche :)

          -
          Edité par QuentinSchifferle 18 octobre 2018 à 11:49:34

          • Partager sur Facebook
          • Partager sur Twitter
            18 octobre 2018 à 13:13:16

            Pourquoi le DISTINCT ? Dans la table région tu as plusieurs fois la même région ?

            • Partager sur Facebook
            • Partager sur Twitter
            Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
              18 octobre 2018 à 13:53:29

              De la manière dont je l'ai fait, certaines régions ressortaient plusieurs fois, du coup le distinct m'a permis de remédier à ça
              • Partager sur Facebook
              • Partager sur Twitter

              Grouper des données en SQL

              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
              • Editeur
              • Markdown