如何在laravel雄辩中进行子查询?

时间:2017-05-04 10:47:24

标签: php laravel laravel-5.3 laravel-eloquent

当我使用db raw时,它可以正常工作

我的查询是这样使用db raw:

$products = DB::select(DB::raw('SELECT * 
                FROM (
                    SELECT a.*, b.name AS store_name, b.address
                    FROM products a
                    JOIN stores b ON b.id = a.store_id
                    WHERE a.category_id = '.$category_id.'
                    ORDER BY a.total_sold DESC, a.updated_at DESC
                    LIMIT '.$num.'
                ) AS product
                GROUP BY store_id'));

有效。但是我想用laravel eloquent来改变它

我试着这样:

$products = Product::where('category_id', '=', $category_id)
     ->with('store')
     ->groupBy('store_id')
     ->orderBy('total_sold','desc')
     ->orderBy('updated_at', 'desc')
     ->take($num)
     ->get();

它也有效。但是orderBy updated_at没有执行

我该如何解决?

1 个答案:

答案 0 :(得分:0)

在我看来,你正在错误地使用群组。即使您在查询之前检索到正确的查询结果,无论如何它都是偶然的。 Group by应该用于聚合查询结果并获取聚合列值。如果使用不正确,选择实际上未聚合的列可能会很危险。

从版本5.6的Mysql文档:

  

MySQL扩展了GROUP BY的标准SQL使用,以便选择列表可以引用GROUP BY子句中未命名的非聚合列。这意味着前面的查询在MySQL中是合法的。您可以通过避免不必要的列排序和分组来使用此功能来获得更好的性能。但是,当GROUP BY中未命名的每个非聚合列中的所有值对于每个组都相同时,这非常有用。服务器可以自由选择每个组中的任何值,因此除非它们相同,否则所选的值是不确定的。此外,添加ORDER BY子句不会影响每个组中值的选择。选择值后会发生结果集排序,ORDER BY不会影响服务器选择的每个组中的值。

此外,从MySql 5.7.5开始,默认的SQL模式包括ONLY_FULL_GROUP_BY标志,该标志将:

  

拒绝选择列表,HAVING条件或ORDER BY列表引用非聚合列的查询,这些列既不在GROUP BY子句中命名,也不在功能上依赖于(由GROUP BY列唯一确定)。

出于教育目的,您应该能够像这样使用Laravel完全相同的查询(未经测试且不使用表别名),但我会避免使用它:

$subQuery = Products::selectRaw('products.*, stores.name as store_name, stores.address')
    ->join('stores', 'stores.id', '=', 'products.store_id')
    ->where('products.category_id', '=', $category_id)
    ->orderBy('products.total_sold', 'DESC')
    ->orderBy('products.updated_at', 'DESC')
    ->take($num)

$products = DB::table(DB::raw('(' . $subQuery->toSql() . ') t'))
    ->groupBy('store_id')
    ->setBindings($subQuery->getBindings())
    ->get();

但对我而言,您尝试做的事情似乎是将所有商店与所需类别的产品结合在一起。因此,Laravel解决方案可能类似于:

Stores::with(['products' => function($productsQuery) use ($category_id) {
    // This limits all the retrieved products to the provided category
    $productsQuery
        ->where('category_id', '=', $category_id)
        ->orderBy('total_sold', 'DESC')
        ->orderBy('updated_at', 'DESC');
}])->whereHas('products', function($productsQuery) use ($category_id) {
    // This makes sure that the store actually has at least one product from the category
    $productsQuery->where('category_id', '=', $category_id);
})->get();

我可能通过查看你的查询做出错误的假设,但目前没有多大意义......无论如何我都会从那里开始。