2017-05-04 25 views
0

当我使用DB原料,它的工作原理如何在laravel雄辩中进行子查询?

我的查询使用DB原料是这样的:

$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雄辩

我尝试这样的:

$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未执行

我该如何解决?

+0

你能粘贴' - > toSql()'吗?让我们知道查询 –

+0

@Agam Banga,'select * from products where category_id =? group by store_id order by total_sold desc,updated_at desc limit 4' –

+0

从sql中,似乎查询已经更新了列。你面临什么问题? –

回答

0

在我看来,你正在使用不正确的组。即使您在查询之前检索到正确的查询结果,但无论如何也是偶然的。分组依据应该用于聚合查询结果并获得聚合列值。如果使用不正确,选择实际未汇总的列可能会很危险。

从MySQL文档为5.6版本:

的MySQL扩展了标准SQL使用GROUP BY的,这样的选择列表可参考在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(); 

我可能会通过看你的查询作出错误的假设,但它并没有在此刻多大意义......我就从那里开始呢。