Mysql 雄辩:如何连接直接相关表和间接相关表?

Mysql 雄辩:如何连接直接相关表和间接相关表?,mysql,laravel,eloquent,laravel-5.2,laravel-5.3,Mysql,Laravel,Eloquent,Laravel 5.2,Laravel 5.3,为了演示我的问题,我创建了一个虚拟数据库,其中包含以下4个表(定义为雄辩的模型):用户、产品、ShoppingItem(short:Item)、订单;与他们的所有相关关系。(此处包含的用户仅用于完整性) 产品: 身份证 名字 有许多(项目) 订单: 身份证 用户id 日期 有许多(项目) 项目: 身份证 产品标识 订单号 belongsTo(产品) belongsTo(订单) 因此,每当客户购买某些产品时,就会创建(购物)项目记录。订单(购物卡丁车)也会创建,其中包含一个或多个项目,

为了演示我的问题,我创建了一个虚拟数据库,其中包含以下4个表(定义为雄辩的模型):用户、产品、ShoppingItem(short:Item)、订单;与他们的所有相关关系。(此处包含的用户仅用于完整性)
产品:

  • 身份证
  • 名字
  • 有许多(项目)
订单:

  • 身份证
  • 用户id
  • 日期
  • 有许多(项目)
项目:

  • 身份证
  • 产品标识
  • 订单号
  • belongsTo(产品)
  • belongsTo(订单)
因此,每当客户购买某些产品时,就会创建(购物)项目记录。订单(购物卡丁车)也会创建,其中包含一个或多个项目,这些项目恰好属于一个客户(用户)及其当前购物流程

现在这个问题是关于产品列表和分析其“成功”的方法。多久卖出一次?最后一次卖出是什么时候?

例如,我可以使用以下查询获取单个产品的所有订单,从而计算它们的销售频率:

$orders = Order::whereHas('items', function ($query) use ($id) {
    $query->where('product_id', $id) 
          ->where('date', '<', Carbon::now());
})->orderBy('date', 'desc')->get();
但我想获得所有产品的列表,按上次订购(购买)的日期排序。该结果必须是一个有说服力的查询或查询生成器集,以便我可以对其进行分页

我在我的产品模型中定义了一个变量,如下所示:

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 }}
然而,我不能在一个雄辩的OrderBy语句中使用“上次售出”这个词

是否有另一种方法可以在不丢失分页功能的情况下,在上述数据库关系中获取产品的“上次售出”值

最终,查询Products表并在上次订购时订购产品的正确方式是什么?


请注意,商品没有日期,只有订单(购物车)才有日期。

使用左键连接
商品和
订单
表,按
产品分组
和按
最大订单(orders.date)

这将执行以下查询:

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的默认设置),则需要在
groupBy()子句中包含
products
表中的所有列

注3:对于从未订购过的产品,
上次订购的
列将为空。在MySQL中,NULL在使用
ASC
时首先排序,在使用
DESC
时最后排序。但这并没有记录在案。因此,如果您不想依赖这种行为,请使用:

->orderbyRaw('max(orders.date) is null')
->orderBy('last_ordered', 'desc')

根据您执行此查询的频率,最好为产品上的时间戳创建一个“last_ordered”列,并在每次有订单时触摸它。

如果项目没有日期,这是如何
$query->where(‘date’、‘好问题!’但出于某种原因,它是有效的……而‘date’实际上是一个表订单字段,其中‘product_id’是一个表项字段。因此在该子查询中,它显然允许我混合两个表中的字段名——只要它们有不同的名称,我猜。我决不是雄辩方面的专家……我可以得到一个列表l带有产品详细信息和实际购物卡丁车(订单)日期的购物项目,按此日期订购如下:
$items=Item::with('product','order')->orderBy('product_id','date')
,但会生成所有项目的列表,而不是所有产品的列表(要小得多)。这些表中还有其他列吗(特别是项目表)?当然,还有很多。这些只是能够重现/演示问题的最低要求。你完全正确,但实际上这不是一个非常频繁的查询。
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
->orderbyRaw('max(orders.date) is null')
->orderBy('last_ordered', 'desc')