【问题标题】:Laravel eloquent order by sum of hasMany or by joinLaravel eloquent order by sum of hasMany 或 by join
【发布时间】:2021-03-02 05:06:03
【问题描述】:

我想由最喜欢的人订购我的产品。我有一张产品表、一张喜欢表和一张用户表。

这是我的喜欢表的样子: id, user_id, product_id, value

value 可以是 1-1,表示喜欢或不喜欢。

在我的产品模型中,我定义了这些关系:

public function likes()
{
    return $this->belongsToMany('App\Models\User', 'products_likes', 'product_id', 'user_id')->withPivot('value')->withTimestamps();
}

public function productLikes()
{
    return $this->hasMany('App\Models\ProductLike');
}

但是,现在我想获得sum 点赞最多的前 20 个产品。 这就是我试图解决这个问题的方法,但是,我无法解决我的问题......

$products = Product::select('products.*', DB::raw('SUM(products_likes.value) as sumLikes'))
            ->join('products_likes', 'products_likes.product_id', '=', 'products.id')
            ->orderBy('sumLikes', 'DESC')
            ->get();

但是,这会导致一个奇怪的 group by sql 问题:

QLSTATE[42000]: Syntax error or access violation: 1140 Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause (SQL: select `products`.*, SUM(products_likes.value) as sumLikes from `products` inner join `products_likes` on `products_likes`.`product_id` = `products`.`id` order by `sumLikes` desc) 

有谁知道我可以如何存档? 我想让我的数据库来执行排序工作,而不是 Laravel。我在这里也找到了一些解决方案,但他们建议执行all()with("likes") 查询并在查询执行后使用sortByDesc (here)。但这会降低性能。

亲切的问候

【问题讨论】:

  • 这个错误没有什么奇怪的:如果您使用聚合函数(COUNT、SUM 等),您选择的所有其他列都必须是您的 GROUP BY 子句的一部分
  • 但是为什么会这样?有没有更好的方法来执行这个查询?

标签: php mysql laravel sum sql-order-by


【解决方案1】:

从 laravel 5.2 开始,你可以使用 withCount 方法添加一个 'likes_count' 子查询列,可以这样自定义:

Product::query()
    ->withCount(['likes as sumLikes' => function ($query) {
        return $query->select(\DB::raw('SUM(products_likes.value) AS sumLikes'));
    }])
    ->orderBy('sumLikes', 'DESC')
;

通过自己编写子查询,可以在 Laravel 5.1 或更早版本上实现类似的结果:

$subquery = ProductLike::query()
    ->selectRaw('SUM(product_likes.value) as sumLikes')
    ->whereRaw('product_likes.product_id = products.id')
;
Product::query()
    ->addSelect(DB::raw($subquery->toSql()))
    ->orderBy('sumLikes', 'DESC')
;

另一种方法是使用连接,就像您尝试的那样,但您需要按产品分组才能使其工作。

Product::query()
    ->addSelect(DB::raw('SUM(products_likes.value) as sumLikes'))
    ->join('products_likes', 'products_likes.product_id', '=', 'products.id')
    ->groupBy('products.id')
    ->orderBy('sumLikes', 'DESC')
;

您可能需要在选择中指定列,并按每一列分组,具体取决于您的数据库引擎。

【讨论】:

  • 我已经尝试了上面的答案和最后一个。第一个对我不起作用。我不知道为什么,但是 Laravel 使用 count(*) 而不是 sum(value) 进行子查询......我不知道为什么,你呢?第三个答案是因为join 而多次退还我的物品。你知道如何修正第一个答案吗?
  • 出于某种原因,它适用于 DB::Raw,但不适用于 select raw
猜你喜欢
  • 1970-01-01
  • 2018-03-29
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-03
  • 1970-01-01
相关资源
最近更新 更多