2009-03-28 7 views
0

Je cette PHP/code MYSQL qui renvoie les enregistrements d'une table commandée par leurs notes, de mieux notés à évalué le plus bas:Mysql Classez par - mais capturer tous

<table width="95%"> 
    <tr> 
    <?php 
     if (isset($_GET['p'])) { 
      $current_page = $_GET['p']; 
     } else { 
      $current_page = 1; 
     } 
     $cur_category = $_GET['category']; 
     $jokes_per_page = 40; 
     $offset = ($current_page - 1) * $jokes_per_page; 

     $result = mysql_query(" 
     select jokedata.id as joke_id, jokedata.datesubmitted as datesubmitted, 
     jokedata.joketitle as joke_title, sum(ratings.rating)/count(ratings.rating) as average 
     from jokedata inner join ratings 
     on ratings.content_type = 'joke' and ratings.relative_id = jokedata.id 
     WHERE jokecategory = '$cur_category' 
     group by jokedata.id 
     order by average desc 
     limit $offset, $jokes_per_page 
     "); 

     $cell = 1; 
     while ($row = mysql_fetch_array($result)) { 
      if ($cell == 5) { 
       echo "</tr><tr class=\"rowpadding\"><td></td></tr><tr>"; 
       $cell = 1; 
      } 
      $joke_id = $row['joke_id']; 
      $joke_title = $row['joke_title']; 
      $joke_average = round($row['average'], 2); 

      echo "<td><strong><a class=\"joke_a\" href=\"viewjoke.php?id=$joke_id\">$joke_title</a></strong> -average rating $joke_average.</td>"; 
      $cell++; 
     } 
    ?> 
    </tr> 
    <tr class="rowpadding"><td></td></tr> 
</table> 

Il fonctionne parfaitement, mais il y a une problème - si un élément n'a pas au moins une note, il ne sera pas du tout sélectionné par la requête!

Comment puis-je y remédier? Merci.

Répondre

1

Vous devez utiliser une jointure gauche plutôt qu'une jointure interne, puis gérer le cas où ratings.ratings est nulle:

$result = mysql_query(" 
      SELECT jokedata.id AS joke_id, 
      jokedata.datesubmitted AS datesubmitted, 
      jokedata.joketitle AS joke_title, 
      -- average is 0 if count or sum is null 
      IFNULL(SUM(ratings.rating)/COUNT(ratings.rating), 0) AS average 
      FROM jokedata 
      -- return all rows from left table (jokedata), and all nulls for ratings 
      -- data when there is no matching row in the right table (ratings) 
      LEFT JOIN ratings ON ratings.content_type = 'joke' AND jokedata.id = ratings.relative_id 
      WHERE jokecategory = '$cur_category' 
      GROUP BY jokedata.id 
      ORDER BY average desc 
      LIMIT $offset, $jokes_per_page 
      "); 

La jointure gauche renverra tous les résultats de jokedata et vont tout simplement revenir tous null pour les évaluations pour chaque ligne où la condition de jointure n'est pas remplie.

+0

Désolé, mais il est toujours pas les sélectionner. –

1

Je recommande ce qui suit:

  • utilisation left outer join pour obtenir des blagues qui ont aucune cote
  • utilisation avg() au lieu de la moyenne
  • calculer manuellement peut-être utiliser coalesce() pour éviter null valeurs dans le résultat

Voici une version simplifiée de vos tables:

create table joke(jokeid int primary key, jokedata varchar(50)); 
create table ratings(rating int, relative_id int); 
insert into joke values(1, "killing"); 
insert into joke values(2, "no rating"); 
insert into ratings values(5, 1); 
insert into ratings values(10, 1); 

Et quelques exemples de requêtes:

select joke.jokeid, avg(ratings.rating) as average 
    from joke 
    left outer join ratings 
    on ratings.relative_id = joke.jokeid 
    group by joke.jokeid; 
+--------+---------+ 
| jokeid | average | 
+--------+---------+ 
|  1 | 7.5000 | 
|  2 | NULL | 
+--------+---------+ 

Ou, en utilisant coalesce():

select joke.jokeid, avg(coalesce(ratings.rating, 0)) as average 
    from joke 
    left outer join ratings 
    on ratings.relative_id = joke.jokeid 
    group by joke.jokeid; 
+--------+---------+ 
| jokeid | average | 
+--------+---------+ 
|  1 | 7.5000 | 
|  2 | 0.0000 | 
+--------+---------+ 
0

Il me semble que l'utilisation de la moyenne est un peu injuste. Si Joke A a 1 note de 5 et Joke B a 25 notes de 4, alors Joke A se classera au-dessus de Joke B. Cela donne des blagues impopulaires plus d'un avantage d'être classé plus haut.

Je suggérerais d'associer le poids aux classements, puis de les classer en fonction du poids. Par exemple, sur une échelle de 1 à 5, 1 obtiendrait -2, 2 obtiendrait -.5, 3 est 0, 4 est +.5 et 5 obtiendrait +2. Donc, cela permettrait à une blague avec 5 "4" d'être classé plus haut que la blague avec 1 "5".

L'échelle de -2 à +2 peut nécessiter quelques ajustements, mais j'espère que vous voyez mon point.

1

Essayez ceci:

SELECT jokedata.id as joke_id, 
     jokedata.datesubmitted as datesubmitted, 
     jokedata.joketitle as joke_title, 
     COALESCE(
     (
     SELECT AVG(rating) 
     FROM ratings 
     WHERE ratings.relative_id = jokedata.id 
       AND ratings.content_type = 'joke' 
     ), 0) AS average 
FROM jokedata 
ORDER BY 
     average DESC 
LIMIE $offset, $jokes_per_page 
Questions connexes