为了演示我的问题,我创建了一个虚拟数据库,包含这4个表(定义为Eloquent模型):用户,产品,ShoppingItem(简称:项目),订单;与他们所有相关的关系。 (用户仅为完整性而包含在此处)
的产品:
订单
产品:
因此,只要客户购买某些产品,就会创建(购物)商品记录。还创建了订单(购物卡丁车),其中包含一个或多个属于一个客户的项(用户)和他当前的购物过程
现在这个问题是关于产品清单和分析其“成功”的方法。它们的销售频率和最后一次销售的时间是什么时候?
例如,我可以使用以下查询获取单个产品的所有订单,从而计算它们的销售频率:
$orders = Order::whereHas('items', function ($query) use ($id) {
$query->where('product_id', $id)
->where('date', '<', Carbon::now());
})->orderBy('date', 'desc')->get();
此外,我可以通过以下方式获得所售产品的清单:
$products = Products::withCount('items')
->orderBy('item_count', 'desc');
但我希望得到所有产品的清单,按照上次订购(购买)的日期排序。该结果必须是Eloquent查询或查询生成器集,以便我可以使用分页。
我的产品型号中定义了一个Mutator,如下所示:
public function getLastTimeSoldAttribute( $value ) {
$id = $this->id;
// get list of plans using this song
$order = Order::whereHas('items', function ($query) use ($id) {
$query->where('product_id', $id)
->where('date', '<', Carbon::now());
})->orderBy('date', 'desc')->first();
return $order->date;
}
它返回上次购买此产品的日期,我可以在以下视图中使用它:
{{ $product->last_time_sold }}
但是,我不能在Eloquent OrderBy语句中使用' last_time_sold '!
是否有另一种方法可以在如上所述的数据库关系中获取产品的' last_time_sold ',而不会失去分页的能力?
最终,查询Products表并在上次订购产品时订购产品的正确方法是什么?
请注意,物品没有日期,只有订单(购物卡丁车)有日期。
答案 0 :(得分:1)
对items
和orders
表使用LEFT JOIN,products
分组,MAX(orders.date)
分组。
$products = Product::leftJoin('items', 'items.product_id', '=', 'products.id')
->leftJoin('orders', 'orders.id', '=', 'items.order_id')
->groupBy('products.id')
->selectRaw('products.*, max(orders.date) as last_ordered')
->orderBy('last_ordered', 'desc')
->get();
这将执行以下查询:
select products.*, max(orders.date) as last_ordered
from `products`
left join `items` on `items`.`product_id` = `products`.`id`
left join `orders` on `orders`.`id` = `items`.`order_id`
group by `products`.`id`
order by `last_ordered` desc
注1:如果您只想获取已订购的产品,请使用join()
代替leftJoin
。
注意2:如果使用严格模式运行MySQL(laravel 5.3的默认值),则需要在products
子句中包含groupBy()
表中的所有列。< / p>
注3:对于从未订购的产品,last_ordered
列将为NULL。在MySQL中,NULL在使用ASC
时首先排序,在使用DESC
时排在最后。但AFAIK没有记录。因此,如果您不想依赖该行为,请使用:
->orderbyRaw('max(orders.date) is null')
->orderBy('last_ordered', 'desc')
答案 1 :(得分:0)
根据您执行此查询的频率,最好为产品上的时间戳创建“last_ordered”列,并在每次订单时触摸它。