Laravel Eloquent如何加入查询而不是表?

时间:2016-06-12 02:09:10

标签: php mysql laravel eloquent

我想在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')作为解决方法。只是想知道如何以雄辩的方式做到这一点?感谢。

2 个答案:

答案 0 :(得分:2)

如果你想在这种情况下出于效率原因进行单一查询,那么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()的{​​{1}},则会获得以下内容

getSql()

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

至于Eloquent,你的产品模型甚至没有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 字段(它可能有price函数返回一个关系对象)所以得到一个{{1}是没有意义的模型与单个价格相关联。

修改

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

prices()

这只会运行一个查询,但数据库不会执行Product操作。

答案 1 :(得分:0)

在Eloquent中,跟我来说,你需要与普通的mysql查询略有不同。使用Model而不是复杂的查询。

首先,您需要创建具有关系的产品和价格模型:

<?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方式,您可以使用这样的查询生成器:

$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()