2009-03-28 5 views
0

я это PHP/MYSQL код, который возвращает записи из таблицы упорядочены по их рейтингам, с наивысшим рейтингом до самого низкого рейтинга:Mysql заказ по рейтингу - но захватить все

<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> 

Он отлично работает, но есть один проблема - если элемент не имеет хотя бы одного рейтинга, он не будет выбран по запросу вообще!

Как я могу это исправить? Благодарю.

ответ

1

Вы должны использовать левое соединение, а не внутреннее соединение, а затем обрабатываем случай, когда ratings.ratings равна нулю:

$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 
      "); 

Левый присоединиться возвращает все результаты jokedata и просто вернуть все nulls для оценок для каждой строки, где условие соединения не выполняется.

+0

Извините, но это еще не их выбора. – 2009-03-28 11:39:49

1

Я бы рекомендовал следующее:

  • использовать left outer join, чтобы получить шутки, которые не имеют рейтингов
  • использование avg() вместо ручного вычисления среднего
  • возможно использовать coalesce(), чтобы избежать null значений в результате

Вот упрощенная версия ваших таблиц:

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); 

И некоторые примеры запросов:

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 | 
+--------+---------+ 

Или, используя 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

Мне кажется, что при использовании в среднем немного несправедливо. Если Joke A имеет 1 рейтинг 5 и Joke B имеет 25 рейтингов 4, то Joke A будет стоять выше Шутки B. Это дает непопулярным шуткам больше преимуществ, чтобы быть оцененными выше.

Я бы предложил связать вес с рейтингами, а затем по весу. Например, по шкале от 1 до 5, 1 получит -2, 2 получит a -.5, 3 равно 0, 4 равно + 5 и 5 получит +2. Таким образом, это позволит шутить с рейтингом 5 "4", чтобы быть оцененным выше, чем шутка с рейтингом 1 "5".

Возможно, вам нужна настройка 1-2 до +2, но, надеюсь, вы увидите мою точку зрения.

1

Попробуйте это:

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