PHP Eviter les doublons

Résolu
Bonjour,
J'aimerais lister des évènements en les regroupant par date ; jusque là, pas de problèmes.
Sauf que ça me fait des doublons, car le script va chercher, pour un évènements donné, chaque autre évènement qui a la même date. Du coup, pour un autre évènement donné, si le premier a la même date, alors il le réaffiche... Je vois très bien pourquoi, mais pour ce qui est de régler le problème, c'est autre chose...
Donc si quelqu'un peut m'aider, ça pourrait bien m'arranger :)
Je donne mon code :

$select01 = mysql_query("SELECT * FROM event" . $tblid . " ORDER BY date") or die(mysql_error()); 
  
 // On fait une boucle pour lister tous les events 
 while($eventslist = mysql_fetch_array($select01)) 
 { 
  // Ce qui suit fonctionne mais il y a des doublons, car il affiche pour chacun ses équivalents (event1.date = event2.date et event2.date = event1.date) 
  $nombre = 5;  
   
  // On sélectionne tous les events dont la date correspond à celle de l'event clé de la boucle while 
  $select02 = mysql_query("SELECT * FROM event" . $tblid . " WHERE date='" . $eventslist['date'] . "'") or die('Yo die'); 
  $rows = mysql_num_rows($select02); 
  if ($rows == 1) 
  { 
   echo '' . $eventslist['date'] . '<br/>' . $eventslist['date'] . '<br/><br/>'; 
   echo '<br/><br/>'; 
  } 
  else if ($rows >= 1) 
  { 
   echo '' . $eventslist['date'] . '<br/>'; 
   //On fait une boucle qui, dans la boucle, liste tous les events de même de date ensembles 
   while ($listbydate = mysql_fetch_array($select02)) 
   { 
    echo '' . $listbydate['event'] . ''<br/>'; 
   } 
   echo '<br/><br/>'; 
  } 
 } 


Donc tout ça me donne :

Date 1
Event 1

Date 2
Event 2

Date 3
Event 3
Event 4

Date 3
Event 3
Event 4

Date 4
Event 5

Alors que je voudrais simplement

Date 1
Event 1

Date 2
Event 2

Date 3
Event 3
Event 4

Date 4
Event 5

Merci d'avance pour l'aide :)

7 réponses

Résumé de la discussion

Lister des événements par date dans le script provoque des doublons lorsque plusieurs événements partagent la même date, car la recherche pour chaque élément réaffiche les autres occurrences ayant cette date. Plusieurs approches sont évoquées, notamment l’utilisation de DISTINCT dans la requête, des requêtes imbriquées pour regrouper par date, ou encore une logique qui lit date et regroupe les événements correspondants. Des solutions plus propres proposent de mémoriser les dates déjà vues et d’assembler les événements potentiels sous chaque date, ou d’opter pour des regroupements via GROUP BY et concaténation, selon le volume et les besoins.

Bobot (l’IA à votre service)
  1. Contributeur
    Salut,
    Deux choses : pourquoi te casse à refaire une multitude d'appels MySQL alors que tu obtiens déjà tous les événements classés par date ? Tu as déjà dans ta première réponse SQL tout ce qu'il faut !

    Sinon ton problème doit venir tu fais que tu fais un if (==1) suivi d'un else if (>=1). Donc dans le cas où ça vaut 1, tu passes dans les deux. Il faut remplacer le >= par un > tout court.

    Mais encore une fois ce code est lourd inutilement.
    0
    1. Contributeur
      Une idée de solution plus propre :

      $memDate = 0;   // Sert à retenir la date de l'événement précédent
      $memEvenement = "";   // Sert à créer petit a petit le code des événements ayant la même date
      $iCompteur = 0;   // Sers uniquement à détecter le premier passage dans la boucle
      
      while($eventslist = mysql_fetch_array($select01)){
         if ($iCompteur > 0){
            if ($eventslist['date'] != $memDate){  //Nouvelle date
               echo ($memDate."<br/>".$memEvenement."<br/><br/>");
               $memDate = $eventslist['date'];
               $memEvenement = "";
            } else { // cas d'une date déjà vue
               $memEvenement = $memEvenement."<br/>".$eventslist['events'] ;
            }
         } else { // cas du premier passage dans la boucle
            $memDate = $eventslist['date'];
            $memEvenement = $eventslist['events'];
         }
         $iCompteur++;
      }


      Normalement ça doit marcher, mais avec l'éditeur de CCM j'ai pu faire quelques erreurs :)
      0
      1. Et sinon, plus simple :
        $lastDate = '';
        $result = '';

        while($row = mysql_fetch_array($select01)){
        if( $row['date'] !== $lastDate )
        {
        $result .= (empty($lastDate)?'':"<br/>").$row['date'];
        $lastDate = $row['date'];
        }
        $result .= "<br/>".$row['event'];
        }

        ( @Mihawk : Autant utiliser la variable de dernière date pour tester s'il s'agit ou non du 1er passage ;) )
        0
      2. Contributeur
        Deux choses :
        1- Je ne comprends pas trop la fermeture de parenthèse de ton code à la ligne définissant $result ;
        2- Tu oublie le principal : écrire :-)

        Sinon en effet le compteur dans mon code me génait mais j'avais la flemme de me creuser la tête à trouver une autre solution... bien vu !
        0
      3. Il n'y a pas de parenthèse à la ligne qui définit $result (2e ligne). Par contre, il y en a sur l'une des post-concatenations ( .= ).
        Il s'agit d'un ternaire : c'est comme un "if/then/else" mais en condensé.

        Ton code ne faisait aucun affichage non plus :p
        0
    2. Merci pour vos réponses, je dois dire que de chercher des tas de solutions, en faisant du bricolage, je me suis perdu au milieu des lignes de code, pour ça que ça ressemblait à une usine à gaz...

      Je me suis donc inspiré de A.Nonymous

      $select01 = mysql_query("SELECT * FROM event" . $tblid . " ORDER BY date") or die(mysql_error()); 
      
        
       $lastDate = '';  
      
       while($row = mysql_fetch_array($select01)) 
       {  
        if( $row['date'] !== $lastDate )  
        {  
         $lastDate = $row['date'];  
         echo '<br/><br/>' . $row['date'] . ''; 
         echo '<br/>' . $row['event'] . ''; 
        }  
        else 
        { 
         echo '<br/>' . $row['event']; 
        } 
       }  
      


      Tout simple, effectivement, je me suis trop pris la tête inutilement.

      Par contre, je n'ai pas utilisé $result, je n'ai pas compris d'abords sa syntaxe, ni son intérêt :s ça semble fonctionner sans.

      A un détail près : toutes mes dates sont de 2011, sauf une, qui est 2001.
      Toutes s'affichent, avec le groupement que je veux pour les dates communes, mais pas celle de 2001... Je ne vois pas dans le code un quelconque élément excluant une date telle que 2001 en gardant les 2011... Des idées ?
      [edit] En fait c'est simplement le 1er enregistrement qui n'est pas pris, ou du moins la 1ere date (issue du ORDER BY). Mais je ne vois pas plus pourquoi...

      Pour ce qui est du DISTINCT, apparemment cette fonction arrête de scanner à la première concordance trouvée, or, je peux en avoir plusieurs, donc à priori c'est trop limité dans mon cas.

      Merci à tous en tout cas ;)
      0
      1. Résolu en haut à droite ;)
        0
      2. Bah en fait pas totalement ^^ vu que j'ai toujours pas la 1ere entrée de mon array
        0
      3. Tu peux duppliquer la première ligne afin d'éviter le problème. Sinon c'est probablement que tu commences la recherche à la seconde ligne, cad celle d'indice 1, et non 0, or ton élément est à l'indice 0, donc la recherche passe à côté.
        0
      4. Contributeur
        bizarre pour ton commentaire sur distinct, je n' ai jamais eu ce souci , enfin je suis content que tu aies trouvé ta solution!
        0
      5. bah c'est écrit dans le lien que tu as donné qui explique la fonction ;)
        0
    3. Contributeur
      Hello,
      Dans ton while, avant le if, rajoute la ligne suivante :

      echo($row['date']);


      Et vois si la ligne de 2001 s'affiche : si oui c'est que le problème vient du while qui ne l'affiche pas, sinon c'est que cela vient de la requête MySQL... Mais la vyant je ne comprends pas pourquoi ça fait ça !
      0
      1. Désolé, j'ai oublié de le préciser, mais c'est réglé depuis hier soir, en fait j'avais une ligne au-dessus du while qui faisait déjà un fetch_array de select01, sauf que je n'utilisais pas son résultat. C'était une ligne que j'avais faite pour tester un autre truc, et sans cette ligne, j'ai bien ma 1ere entrée ;)

        Par contre (vous allez me trouver chiant XD), maintenant que j'arrive à regrouper les events par date, est-ce possible de les trier par heure ? Car pour le moment j'ai :

        Date 1
        Heure 1 - Event 1
        Heure 2 - Event 2

        Sauf que si Heure 2 est 10h30 alors que Heure 1 est 17h00, bah dans l'affichage c'est pas terrible :s

        Donc je ne sais pas si je peux trier par heure, une fois les events regroupés. J'ai peur que ça fasse beaucoup de conditions qui au final se bloquent les unes les autres.
        0
      2. Order by
        0
      3. Oui mais j'ai deja un ORDER BY pour trier par date, ensuite, vu que je voulais regrouper par date sans doublon, c'est lorsque le programme scanne l'event suivant, si c'est la meme date, il le met avec. Mais si l'heure du suivant est anterieure au premier, il le met a la suite sans se soucier de l'heure. Mais je vois pas comment refaire un ORDER BY une fois dans la boucle while. Encore si je pouvais connaitre l'heure du suivant au moment le programme fais la boucle, ca irait, je pourrais choisir l'ordre d'affichage. Mais vu que le while se contente de scanner un à un les entrées, je sèche. :s
        0
      4. Quel est le format du champ date ? Où est stockée l'heure ?
        0
      5. Tu peux faire des select imbriqués sinon
        0
    4. dans ta requette tu mets

      ....ORDER BY date, heure si ton champ contenant l'heure se nomme ainsi
      0
      1. Haaaan je savais pas qu'on pouvais mettre plusieurs arguments derrière un ORDER BY.... lol
        Merci beaucoup, voilà de quoi régler mon problème :)
        0
      2. ^^' pense à mettre résolu en haut à droite !
        0
      3. Hmmm, c'est parce que je bigle que je vois pas le bouton "résolu" ? ou parce que je suis pas un utilisateur enregistré ? je peux même pas éditer mon premier message pour mettre résolu dans le titre...
        0
      4. Humm en principe tu peux, c'est vers ton titre, sur la droite il me semble ^^'
        0
      5. Bah je l'ai "signalé comme résolu", je pense que ce sera fait par un modérateur.
        0