【问题标题】:How to get average with orderBy Desc in Laravel 5如何在 Laravel 5 中使用 orderBy Desc 求平均值
【发布时间】:2018-07-09 19:31:01
【问题描述】:

我的数据库中有 2 个表。

booksratings

books id, name

ratings

idbook_idrating

我已经为这些模型设置了很多关系。

所以在Book 模型中 -

public function ratings()
{
    return $this->hasMany('App\Rating');
}

Rating 模型中-

public function book()
{
    return $this->belongsTo('App\Book');
}

现在我想获取所有具有平均评分但按高评分排序的书籍。

所以我先是高评分的书,然后是低评分。

那么我如何加入 2 个表来实现这个结果。

谢谢。

【问题讨论】:

  • 我不会在这方面使用 ORM。怀疑它会扩展。利用数据库。获取排名和PK,然后在分页后使用ORM并通过ID加载少数。换句话说,使用 SQL。
  • 感谢您的回复。那么我如何在 SQL 中做到这一点呢?

标签: php mysql laravel laravel-5 eloquent


【解决方案1】:

您可以使用修改后的withCount()

$books = Book::withCount(['ratings as average_rating' => function($query) {
    $query->select(DB::raw('coalesce(avg(rating),0)'));
}])->orderByDesc('average_rating')->get();

【讨论】:

  • 如果我的列是浮动的,它是如何工作的?现在我得到了意想不到的结果。 9.5 得到第一个结果,然后 10.0 是因为浮点值而发生的吗?这里是dd - prntscr.com/k4h4kv
  • 我获得了 9.5 的第一个记录和 10.0 的第二个记录,但我希望第一个记录是 10.0,然后是 9.5
  • 请将->get()替换为->toSql():结果如何?
  • 我找到了这篇文章。我正在使用 mysql 5.6。也许这是我的 mysql 中的一个错误?
  • 您没有使用我回答中的代码。没有ORDER BY
【解决方案2】:
Books::withAvg('ratings', 'rating')->orderBy('ratings_avg_rating', 'desc')->take(5)->get();

这适用于 Laravel 8

【讨论】:

    【解决方案3】:

    通过Collections*

        $books = Book::with('ratings')
            ->get()
            ->sortBy(function($bk, $key) {
                if($bk->rating) {
                    return $bk->rating->rating;
                }
                return null;
            });
    

    通过连接

      $books = Book::join('rating', 'rating.book_id', '=', 'book.id')
                     ->orderBy('ratings.rating', 'desc')
                     ->select('books.*')
                     ->get();
    

    【讨论】:

    • 你的第一个方法没有使用 ORM,它会使用 Laravel 的集合方法,因为你试图在 get() 之后执行排序操作,但是,我认为你的意思是 sortBy 而不是 orderBy .
    • @Devon,谢谢你我已经更正了答案并链接到集合文档。也是的,我的意思是 sortBy 以及
    • 如果我想计算平均评分然后根据 OrderBy DESC 得到结果呢??
    【解决方案4】:

    该查询看起来像这样:

    SELECT book.id, AVG(ratings.rating) AS avg_rating 
    FROM ratings
    JOIN book ON book.id = ratings.book_id
    /* WHERE AVG(ratings.rating) > 4 You could say only return results where rating > 4 */
    GROUP BY book.id
    ORDER BY AVG(ratings.rating) DESC LIMIT 5;
    

    您需要连接这两个表,在书上使用带有 group by 的聚合函数。然后只需对结果进行排序和限制。

    更新:

    回答您的问题:

    SELECT book.id, COALESCE(AVG(ratings.rating), 0) AS avg_rating 
    FROM book
    *LEFT* JOIN ratings ON book.id = ratings.book_id    
    GROUP BY book.id
    ORDER BY AVG(ratings.rating);
    

    使用 view 可能是 ORM 的易用性和查询的合理性之间的某种折衷。

    【讨论】:

    • 感谢您的回复。通过这样做,我只会得到那些有评级的书。在我的情况下,我需要得到所有的书。如果一本书没有任何评级,那么它应该给出结果 0。所以现在我在这里得到这样的数据:prnt.sc/k4gluv 但是在我的数据库中我有更多的书,但结果我只得到了那些有评级的书。我需要去取所有的书。
    • 好的。 limit 那么没有意义吧?要完成它,只需反转连接方向。如果您使用 RDBMS,强烈建议学习 SQL。仅仅使用 ORM 而不了解幕后发生的事情并不理想。
    • 是的。我不需要limit。反转加入方式?你能更新你的答案吗?
    • 它给了我这个结果。 prntscr.com/k4gvg9 在我的数据库中,我有 12 本书。但它仍然只得到那些有评级的书
    • Force LEFT JOIN... 查看其他答案(withCount),它看起来使用 ORM,但也是一种理智的检索和聚合方法。
    猜你喜欢
    • 2019-03-29
    • 1970-01-01
    • 1970-01-01
    • 2019-04-17
    • 1970-01-01
    • 1970-01-01
    • 2015-08-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多