Har*_*son 6 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;
Run Code Online (Sandbox Code Playgroud)
我写了这个,但显然有一些错误:
$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();
Run Code Online (Sandbox Code Playgroud)
我得到的错误:
ErrorException in Grammar.php line 39:
Object of class Illuminate\Database\Eloquent\Builder could not be converted to string.
Run Code Online (Sandbox Code Playgroud)
我目前正在使用它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')作为一种解决方法.只是想知道如何以雄辩的方式做到这一点?谢谢.
如果您出于效率原因想要进行单个查询,在这种情况下,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();
Run Code Online (Sandbox Code Playgroud)
如果你改变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
Run Code Online (Sandbox Code Playgroud)
不幸的是,据我所知,没有 DB::raw 就无法使用子查询,但是只要您不将用户输入放入查询中,它就不是不安全的。即使在这种情况下,您也可以通过使用 PDO 安全地使用它。
至于 Eloquent,您的产品模型甚至没有price字段(它可能有一个返回关系对象的函数),因此获取与其关联的单一价格的模型prices()是没有意义的。Product
编辑:
您还可以预先加载关系,即(假设您将模型关系设置为 Trong Lam Phan 的示例)
$products = Product::with('prices')->get();
foreach ($products as $product)
{
$minPrice = $product->prices->min('price');
// Do something with $product and $minPrice
}
Run Code Online (Sandbox Code Playgroud)
这只会运行单个查询,但该min()操作不是由数据库完成的。
在 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');
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您需要选择所有产品:
$products = \App\Product::get();
foreach ($products as $product)
{
$minPrice = $product->prices->min('price');
echo 'Min price of product ' . $product->name . ' is: ' . $minPrice;
}
Run Code Online (Sandbox Code Playgroud)
编辑
如果您对性能有疑问,只需获取产品的 ID 即可。
$products = \App\Product::get(['id']);
Run Code Online (Sandbox Code Playgroud)
如果你不喜欢这种 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();
Run Code Online (Sandbox Code Playgroud)
或者你可以这样做:
\App\Price::join('products', 'prices.product_id', '=', 'products.id')
->selectRaw("name, MIN(price) AS min_price")
->groupBy('product_id')
->orderBy('min_price')
->get()
Run Code Online (Sandbox Code Playgroud)