Mysql 按评级排序 - 但捕获所有

发布于 2024-07-16 04:07:03 字数 1666 浏览 5 评论 0原文

我有这个 PHP/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>

它工作完美,但有一个问题 - 如果一个项目没有至少一个评级,则不会选择它通过查询根本!

我该如何补救? 谢谢。

I have this PHP/MYSQL code which returns records from a table ordered by their ratings, from highest rated to lowest rated:

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

It works perfectly but there is one problem - if an item does not have at least one rating, it will not be selected by the query at all!

How can I remedy this? Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

老旧海报 2024-07-23 04:07:03

我建议如下:

  • 使用 left external 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 | 
+--------+---------+

I would recommend the following:

  • use left outer join to get jokes that have no ratings
  • use avg() instead of manually computing average
  • possibly use coalesce() to avoid null values in the result

Here's a simplified version of your 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);

And some example queries:

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

Or, using 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 | 
+--------+---------+
岁月静好 2024-07-23 04:07:03

您需要使用左联接而不是内联接,然后处理 ratings. ratings 为 null 的情况:

$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 的所有结果,并且仅返回联接条件为的每一行的评级的所有空值没见过。

You need to use a left join rather than an inner join, and then handle the case where ratings.ratings is null:

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

The left join will return all results from jokedata and will just return all nulls for ratings for each row where the join condition is not met.

亚希 2024-07-23 04:07:03

尝试这个:

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

Try this:

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
下壹個目標 2024-07-23 04:07:03

在我看来,使用平均值有点不公平。 如果笑话 A 有 1 个评分为 5,而笑话 B 有 25 个评分为 4,则笑话 A 的排名将高于笑话 B。这使得不受欢迎的笑话更有优势排名更高。

我建议将权重与评级相关联,然后按权重排名。 例如,在从 1 到 5 的范围内,1 会得到 -2,2 会得到 -.5,3 是 0,4 是 +.5,5 会得到 +2。 因此,这将允许具有 5 个“4”评级的笑话比具有 1 个“5”评级的笑话排名更高。

-2 到 +2 的比例可能需要一些调整,但希望你能明白我的观点。

It seems to me that using the average is a little unfair. If Joke A has 1 rating of 5 and Joke B has 25 ratings of 4, then Joke A will rank above Joke B. It gives unpopular jokes more of an advantage to be ranked higher.

I would suggest associating weight to ratings and then ranking by the weight. For example, on a scale from 1 to 5, 1 would get a -2, 2 would get a -.5, 3 is 0, 4 is +.5 and 5 would get a +2. So this would allow a joke with 5 "4" ratings to be ranked higher than the joke with 1 "5" rating.

The -2 to +2 scale may need some tweaking, but hopefully you see my point.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文