Partage
  • Partager sur Facebook
  • Partager sur Twitter

[MySQL] tri sur résultats multiples

    17 juin 2021 à 15:35:05

    Bonjour,

    Je suis plus que novice en SQL et tout l'univers qui l'entoure j'ai tout de même décidé de me plonger dedans pour tenter de simplifier certaines de mes tâches quotidiennes.

    Après deux jours de recherches et de tests infructueux je m'en remets à vous demander de l'aide (ou de gentiment m'expliquer de tout revoir ^^).

    Voici mon souci :

    Dans une table "rapport" j'ai entre autres les colonnes "client" (nom prénom), "date" (date), "relance" (oui / non)

    Chaque jour en arrivant (et au fil de la journée) j'aimerai pouvoir visualiser les clients qui n'ont pas été relancés.

    J'ai trouvé un moyen d'afficher les clients n'ayant pas été relancés MAIS dans cette liste se trouve également les clients ayant été relancés :

    "select
        distinct on
        (client) client, date, relance
    from
        rapport
    where
        date = '2021-06-17'
        and relance = 'non'
    order by
        client desc"

    Exemple de résultat :

    client          | date       | relance |
    ----------------|------------|---------|
    Dupond Roger    | 2021-06-17 | non     |
    Dupont Alfred   | 2021-06-17 | non     |
    Martin Jeanne   | 2021-06-17 | non     |

    Or en faisant une recherche spécifique sur un client particulier j'obtiens le résultat suivant :

    "select
        *
    from
        rapport
    where
        client = 'Dupond Roger'
        and date = '2021-06-17'
    order by
        client desc"


    client          | date       | relance |
    ----------------|------------|---------|
    Dupond Roger    | 2021-06-17 | non     |
    Dupond Roger    | 2021-06-17 | oui     |


    J'aimerai donc dans ma première recherche pouvoir afficher uniquement les clients qui n'ont pas été relancés du tout le jour voulu.

    Je ne sais pas si j'ai su exposer mon problème de façon suffisament claire et si jamais un doute persiste cet exemple est totalement fictif ce qui pourrait expliquer certaines incohérences à la vue d'experts donc n'hésitez pas à me demander des précisions ;)

    Merci d'avance pour votre temps !

    zeZ

    -
    Edité par le_zeZ 17 juin 2021 à 15:39:08

    • Partager sur Facebook
    • Partager sur Twitter
      17 juin 2021 à 16:38:00

      Bonjour,

      Première remarque, si pour une même date tu peux avoir plusieurs rapports, je te conseille fortement de mettre la colonne date en DATETIME (date et heure) pour pouvoir distinguer les enregistrements et leur chronologie ...

      Sinon, une première solution, en l'état, serait d'exclure les clients relancés sur la même journée, avec une jointure externe et une condition IS NULL :

      SELECT R1.*
      FROM
      	rapport R1
      		LEFT JOIN rapport R2
      			ON R1.client = R2.client
      			AND R1.date = R2.date
      			AND R2.relance = 'oui'
      WHERE
      	R1.relance = 'non'
      	AND R1.client = '...'
      	AND R1.date = '...'
      	AND R2.client IS NULL

      Cela risque de te perturber un peu car il y a plein de notions nouvelles (alias, jointure, et jointure externe) ... A analyser au calme :p

      EDIT : Oubli de filtrer R1.relance = 'non'

      -
      Edité par Benzouye 18 juin 2021 à 15:19:09

      • 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 juin 2021 à 15:10:30

        Bonjour Benzouye !

        Merci d'avoir pris le temps d'analyser mon problème et pour la solution proposée.

        Alors en effet la table en question est bien plus fournie en colonnes que les quelques exemples donnés. Il y a entre autres une date pour le jour, une date de début avec horodatage et une date de fin avec horodatage (comme pour une commande par exemple ou la date serait "2021-06-16" la date de début serait par exemple la date d'envoi du colis "2021-06-17 10:34:41" et la date de fin serait la date de réception du colis "2021-06-18 13:15:23").

        Concernant ta proposition j'ai en effet quelques interrogations, ou même incompréhension dues à mon manque de connaissance... J'ai parcouru les fonctions dont tu parles sans certitudes d'avoir bien tout cerné. Le fonctionnement "global" de ta requête proposée m'échappe un peu.

        Je suppose que le "..." dans "R1.client = '...'" et "AND R1.date = '...'" sont des champs à renseigner manuellement.

        Car en fait dans l'exemple j'ai pris 3 entrées dans la colonne "client" mais en réalité j'ai plus de 10 000 entrées. Sans compter les relances donc en fin de journée il peut y avoir jusqu'au double d'entrées.

        Si c'est bien un champ à renseigner que tu indiques là cela ne va pas être possible car je ne peux connaitre les relances faites ou non à moins de rechercher tous les clients un à un (je ne sais pas si je suis très clair encore là). Cette ligne est-elle indispensable ?

        Bien évidement la date du jour je la connais :D

        En faisant un test avec adaptation j'obtiens un résultat incohérent.

        Je ne vais pas avoir plus de temps pour tester tout ça aujourd'hui mais je reviendrais vers toi lundi !

        Merci encore pour ton aide !

        zeZ
        • Partager sur Facebook
        • Partager sur Twitter
          18 juin 2021 à 15:33:26

          le_zeZ a écrit:

          Le fonctionnement "global" de ta requête proposée m'échappe un peu

          Je vais décomposer en deux temps.

          Commençons par :

          SELECT R1.*
          FROM
          	rapport R1
          WHERE
          	R1.relance = 'non'
          	AND R1.client = '...'
          	AND R1.date = '...'

          R1 est un alias, un nom de remplacement, qui permet de ne pas répéter le nom réel de la table, et qui va nous aider pour la deuxième étape.

          Cette requête va lister tous les rapports pour le client et la date donné (en remplaçant les "..." par les valeurs souhaitées) avec relance = non.

          Simple.

          Maintenant, dans cette liste, je vais exclure les rapports pour lesquels il y a aussi un rapport avec relance = oui pour le même client et la même date.

          Pour cela je rajoute une jointure sur la même table (auto-jointure) avec des conditions précises : même client, même date, relance = oui.

          Je définis cette jointure comme externe. Je te laisse creuser cette notion mais en gros cela rend la jointure "facultative", si les conditions de jointures ne sont pas réunies, l'enregistrement à gauche (LEFT) de la jointure est conservé et on obtient NULL côté R2.

          Du coup, en rajoutant R2.client IS NULL dans la clause WHERE je liste les éléments de R1 qui n'ont pas de correspondance dans R2 : "je vais exclure les rapports pour lesquels il y a aussi un rapport avec relance = oui pour le même client et la même date".

          La requête globale :

          SELECT R1.*
          FROM
          	rapport R1
          		LEFT JOIN rapport R2
          			ON R1.client = R2.client
          			AND R1.date = R2.date
          			AND R2.relance = 'oui'
          WHERE
          	R1.relance = 'non'
          	AND R1.client = 'Dupond Roger'
          	AND R1.date = '2021-06-17'
          	AND R2.client IS NULL
          • Partager sur Facebook
          • Partager sur Twitter
          Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL

          [MySQL] tri sur résultats multiples

          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
          • Editeur
          • Markdown