2016-06-12 8 views
3

私はLaravelでこれを達成したい:Laravel Eloquentテーブルではなくクエリで結合する方法を教えてください。

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')を使用しています。この方法を奇妙なやり方でやってみるのはどうでしょう?ありがとう。

+0

あなたは何を製品に与えたいですか?私のSQLスキルが低いので何もしていないからです。 –

+0

@AchrafKhouadja私は私の 'products'テーブルを最低価格で注文したい – Harrison

答えて

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; 
} 

EDIT

パフォーマンスに問題がある場合は、製品のIDを取得してください。

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

あなたが雄弁にこの方法が気に入らない場合、あなたはそのようにクエリビルダを使用することがあります。

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

私は' products'テーブル全体のコレクションを取得したくないので、 sortBy'は非常に遅いです。 – Harrison

+0

はい、そうです。製品表が膨大な場合は、機能しません。私は自分の答えを編集しました。 –

0

効率的な理由から、この場合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(); 

あなたがgetSql()ためget()を変更する場合は、以下の

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なしでサブクエリを使用することはできません::生の知っているように、それにもかかわらず、それは限り安全ではないではありません取得ユーザー入力をクエリーに入れないためです。その場合でも、PDOを使用して安全に使用できます。雄弁については

、お使いの製品モデルは、さらにpriceフィールドがありません(それはおそらく関係オブジェクトを返すprices()機能を持っている)ので、それにasociated単一価格でProductモデルを取得しても意味がありません。

編集:

することもできますeager load関係、すなわち、

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

(あなたがTrongラムファンティエットの例のように設定モデルの関係を持っていると仮定して)これは、単一のクエリを実行しますが、min()操作は、データベースによって行われていません。

関連する問題