将具有许多连接的复杂 SQL 查询转换为 Eloquent
Posted
技术标签:
【中文标题】将具有许多连接的复杂 SQL 查询转换为 Eloquent【英文标题】:Convert complex SQL query with many joins to Eloquent 【发布时间】:2019-08-15 11:03:03 【问题描述】:我有一个有效的 SQL 查询,这是 *** 成员慷慨赠予我的,它可以在 Laravel 中运行:
$actives = DB::select('SELECT a.* ,COALESCE(b.sold,0), sold
FROM ( SELECT * FROM products p
WHERE p.product_type_id = 1
AND DATE(p.visible_date) <= ?
AND p.active = 1
AND (p.end_date >= ? or p.end_date IS NULL) ) a
LEFT JOIN ( SELECT product_id , SUM(quantity) sold
FROM order_items oi JOIN orders o
ON o.id = oi.order_id
AND o.paid is not null
GROUP BY product_id ) b
ON b.product_id = a.id', [Carbon::now(), Carbon::now()]);
但这会返回一个数组,我正在寻找一个集合。我不能使用selectRaw
,因为该方法总是在查询末尾添加FROM tablename
。
我已将 a 和 b 分成子查询,这两个都有效:
$a = DB::table('products')
->where('product_type_id', 1)
->whereDate('visible_date', '<=', Carbon::now())
->where('active', true)
->where(function ($query)
$query->where('end_date', '>=', Carbon::now())
->orWhere('end_date', null);
);
$b = DB::table('order_items')
->selectRaw('product_id , SUM(quantity) sold')
->join('orders', 'orders.id', '=', 'order_items.order_id')
->whereNotNull('orders.paid')
->groupBy('product_id');
Eloquent 查询构建器有一个 leftJoinSub
函数,但文档似乎表明它只适用于将一个查询与一个子查询连接起来,而我似乎需要在两个子查询上连接一个新查询。
有人知道如何将原始 SQL 放入 Eloquent 中,以便我返回 Products 集合而不是数组吗?
【问题讨论】:
【参考方案1】:有一种更简单的方法可以减少数据库的资源消耗
我想你已经声明了Product
和Order
之间的关系顺序
Class Product extends Model
public function getSoldAttribute()
return $this->orderItems()
->select(\DB::raw('SUM(quantity) as sold'))
->join('orders', 'order_items.order_id', '=', 'orders.id')
->whereNotNull('orders.paid')
->groupBy('product_id')
->value('sold');
...
然后您使用您想要的过滤器获取您的产品并访问$product->sold
属性
$products = Products::where('product_type_id', 1)
->whereDate('visible_date', '<=', Carbon::now())
->where('active', true)
->where(function ($query)
$query->where('end_date', '>=', Carbon::now())
->orWhere('end_date', null);
)->get();
foreach($products as $product)
var_dump($product->sold);
您还可以使用protected $appends = ['sold'];
强制加载Product
模型中的sold
属性
【讨论】:
我在Product
和Order
之间没有关系。 Order
和 OrderItem
之间存在关系,Product
和 OrderItem
之间存在关系。我应该创建一个新的 hasManyThrough 吗?
这看起来正是我想要的,但我遇到了错误。首先,我得到Call to undefined method Illuminate\Database\Query\Expression::groupBy()
。另一篇文章说将它移到select
之前,我已经完成了,现在我得到了Call to undefined method Illuminate\Database\Query\Expression::value()
。
@Jacey 你做了return $this->orders->select(
而不是return $this->orders()->select(
。您可以将orders
关系添加到您的问题吗?
我按照您写的方式复制了它,顺便说一句,它缺少括号,但我更正了。我添加了关系public function orders() return $this->hasManyThrough('App\Order', 'App\OrderItem');
是的。这实际上也不是我想要的订单。我想要 Orders.paid 不为空的那个产品 id 的 OrderItems 的总和。以上是关于将具有许多连接的复杂 SQL 查询转换为 Eloquent的主要内容,如果未能解决你的问题,请参考以下文章