【问题标题】:Convert complex SQL query with many joins to Eloquent将具有许多连接的复杂 SQL 查询转换为 Eloquent
【发布时间】:2019-08-15 11:03:03
【问题描述】:

我有一个有效的 SQL 查询,这是 stackoverflow 成员慷慨赠予我的,它可以在 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 集合而不是数组吗?

【问题讨论】:

    标签: laravel laravel-5 eloquent


    【解决方案1】:

    有一种更简单的方法可以减少数据库的资源消耗

    我想你已经声明了ProductOrder之间的关系顺序

    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-&gt;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 属性

    【讨论】:

    • 我在ProductOrder 之间没有关系。 OrderOrderItem 之间存在关系,ProductOrderItem 之间存在关系。我应该创建一个新的 hasManyThrough 吗?
    • 这看起来正是我想要的,但我遇到了错误。首先,我得到Call to undefined method Illuminate\Database\Query\Expression::groupBy()。另一篇文章说将它移到select 之前,我已经完成了,现在我得到了Call to undefined method Illuminate\Database\Query\Expression::value()
    • @Jacey 你做了return $this-&gt;orders-&gt;select( 而不是return $this-&gt;orders()-&gt;select(。您可以将orders 关系添加到您的问题吗?
    • 我按照您写的方式复制了它,顺便说一句,它缺少括号,但我更正了。我添加了关系public function orders() { return $this-&gt;hasManyThrough('App\Order', 'App\OrderItem'); }
    • 是的。这实际上也不是我想要的订单。我想要 Orders.paid 不为空的那个产品 id 的 OrderItems 的总和。
    猜你喜欢
    • 2012-01-01
    • 1970-01-01
    • 2019-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多