【问题标题】:Laravel Eloquent how to join on a query rather than a table?Laravel Eloquent 如何加入查询而不是表?
【发布时间】:2016-06-12 02:09:09
【问题描述】:

我想在 Laravel 中实现这一点:

SELECT * FROM products JOIN
(SELECT product_id, MIN(price) AS lowest FROM prices GROUP BY product_id) AS q1
ON products.id = q1.product_id
ORDER BY q1.lowest;

我写了这个,但显然有问题:

$products = new Product();
$products = $products->join(
    Price::whereNotNull('price')->select('product_id', DB::raw('min(price) as lowest'))->groupBy('product_id'), 'products.id', '=', 'product_id'
    )->orderBy('lowest')->get();

我得到的错误:

ErrorException in Grammar.php line 39:
Object of class Illuminate\Database\Eloquent\Builder could not be converted to string.

我目前正在使用join(DB::raw('(SELECT product_id, MIN(price) AS lowest FROM prices WHERE price IS NOT NULL GROUP BY product_id) AS q1'), 'products.id', '=', 'q1.product_id') 作为解决方法。只是想知道如何以雄辩的方式做到这一点?谢谢。

【问题讨论】:

  • 你能告诉我们,你想给产品什么?因为我的 sql 技能很低,所以我不明白你在做什么
  • @AchrafKhouadja 我想以最低价格订购我的products 餐桌

标签: php mysql laravel eloquent


【解决方案1】:

如果你想在这种情况下出于效率原因进行单个查询,Eloquent 不会对你有太大帮助,这是可能的,但很麻烦。对于这种情况,您有 QueryBuilder。

DB::table('products')
    ->join(
        DB::raw('(SELECT product_id, MIN(price) AS lowest FROM prices GROUP BY product_id) AS q1'),
        'products.id', '=', 'q1.product_id'
    )
    ->orderBy('q1.lowest')->get();

如果您将get() 更改为getSql(),您会得到以下结果

select * from `products` inner join
(SELECT product_id, MIN(price) AS lowest FROM prices GROUP BY product_id) AS q1
on `products`.`id` = `q1`.`product_id` order by `q1`.`lowest` asc

不幸的是,据我所知,您不能在没有 DB::raw 的情况下使用子查询,但只要您不将用户输入放入查询中,它就不是不安全的。即使在这种情况下,您也可以通过使用 PDO 安全地使用它。

至于 Eloquent,您的产品模型甚至没有 price 字段(它可能有一个返回关系对象的 prices() 函数),因此以单一价格获得 Product 模型是没有意义的与之相关。

编辑:

您也可以eager load 关系,即(假设您将模型关系设置为 Trong Lam Phan 的示例)

$products = Product::with('prices')->get();
foreach ($products as $product)
{
    $minPrice = $product->prices->min('price');
    // Do something with $product and $minPrice
}

这只会运行一个查询,但min() 操作不是由数据库完成的。

【讨论】:

    【解决方案2】:

    在 Eloquent 中,跟我来,你需要和普通的 mysql 查询有点不同的想法。使用模型而不是复杂的查询。

    首先,您需要创建产品和价格模型以及它们之间的关系:

    <?php
    
    namespace App;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Product extends Model
    {
        public function prices()
        {
            return $this->hasMany('\App\Price');
        }
    } 
    
    class Price extends Model
    {
        public function product()
        {
            return $this->belongsTo('\App\Product');
        }
    }
    

    然后,您需要选择所有产品:

    $products = \App\Product::get();
    foreach ($products as $product)
    {
        $minPrice = $product->prices->min('price');
        echo 'Min price of product ' . $product->name . ' is: ' . $minPrice;
    }
    

    编辑

    如果您对性能有问题,只需获取产品的 id。

    $products = \App\Product::get(['id']);
    

    如果你不喜欢 Eloquent 的这种方式,你可以像这样使用 Query Builder:

    $result = \App\Price::join('products', 'prices.product_id', '=', 'products.id')
                    ->select('product_id', 'name', \DB::raw("MIN(price) AS min_price"))
                    ->groupBy('product_id')
                    ->orderBy('min_price')
                    ->get();
    

    或者你可以这样做:

    \App\Price::join('products', 'prices.product_id', '=', 'products.id')
            ->selectRaw("name, MIN(price) AS min_price")
            ->groupBy('product_id')
            ->orderBy('min_price')
            ->get()
    

    【讨论】:

    • 我不想收集我的整个products 表并使用sortBy,这非常慢。
    • 是的,你是对的。如果产品表很大,它就不起作用。我已经编辑了我的答案,希望它对你有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-20
    • 1970-01-01
    • 2018-09-21
    • 2020-11-21
    • 2020-08-09
    • 2014-10-13
    • 2021-12-11
    相关资源
    最近更新 更多