2014-11-21 4 views
12

ich folgende Eloquent Abfrage habe (Dies ist eine vereinfachte Version einer Abfrage, das gehe über diesen von mehr where s und orWhere s daher den scheinbaren Umweg besteht - ist die Theorie, was wichtig ist):Wie erstellt man eine Unterabfrage mit Laravel Eloquent?

$start_date = //some date; 

$prices = BenchmarkPrice::select('price_date', 'price') 
->orderBy('price_date', 'ASC') 
->where('ticker', $this->ticker) 
->where(function($q) use ($start_date) { 

    // some wheres... 

    $q->orWhere(function($q2) use ($start_date){ 
     $dateToCompare = BenchmarkPrice::select(DB::raw('min(price_date) as min_date')) 
     ->where('price_date', '>=', $start_date) 
     ->where('ticker', $this->ticker) 
     ->pluck('min_date'); 

     $q2->where('price_date', $dateToCompare); 
    }); 
}) 
->get(); 

Wie Sie sehen können, bin ich pluck das früheste Datum, das auf oder nach meiner start_date auftritt. Dies führt dazu, dass eine separate Abfrage ausgeführt wird, um dieses Datum zu erhalten, das dann als Parameter in der Hauptabfrage verwendet wird. Gibt es eine Möglichkeit eloquent, die Abfragen zu einer Unterabfrage zusammenzufassen und somit nur 1 Datenbankanruf statt 2?

Edit:

Wie pro @ Jareks Antwort auf diese meine Frage ist:

$prices = BenchmarkPrice::select('price_date', 'price') 
->orderBy('price_date', 'ASC') 
->where('ticker', $this->ticker) 
->where(function($q) use ($start_date, $end_date, $last_day) { 
    if ($start_date) $q->where('price_date' ,'>=', $start_date); 
    if ($end_date) $q->where('price_date' ,'<=', $end_date); 
    if ($last_day) $q->where('price_date', DB::raw('LAST_DAY(price_date)')); 

    if ($start_date) $q->orWhere('price_date', '=', function($d) use ($start_date) { 

     // Get the earliest date on of after the start date 
     $d->selectRaw('min(price_date)') 
     ->where('price_date', '>=', $start_date) 
     ->where('ticker', $this->ticker);     
    }); 
    if ($end_date) $q->orWhere('price_date', '=', function($d) use ($end_date) { 

     // Get the latest date on or before the end date 
     $d->selectRaw('max(price_date)') 
     ->where('price_date', '<=', $end_date) 
     ->where('ticker', $this->ticker); 
    }); 
}); 
$this->prices = $prices->remember($_ENV['LONG_CACHE_TIME'])->get(); 

Die orWhere Blöcke verursachen alle Parameter in der Abfrage plötzlich nicht notierte werden. Z.B. WHERE price_date >= 2009-09-07. Wenn ich die orWheres entferne, funktioniert die Abfrage gut. Warum ist das? Diese

Antwort

16

ist, wie Sie eine Unterabfrage zu tun, wo:

$q->where('price_date', function($q) use ($start_date) 
{ 
    $q->from('benchmarks_table_name') 
    ->selectRaw('min(price_date)') 
    ->where('price_date', '>=', $start_date) 
    ->where('ticker', $this->ticker); 
}); 

Leider orWhere erfordert ausdrücklich $operator vorgesehen, sonst wird es einen Fehler aus, so in Ihrem Fall:

$q->orWhere('price_date', '=', function($q) use ($start_date) 
{ 
    $q->from('benchmarks_table_name') 
    ->selectRaw('min(price_date)') 
    ->where('price_date', '>=', $start_date) 
    ->where('ticker', $this->ticker); 
}); 

EDIT: Sie müssen from in der Schließung in der Tat angeben, sonst wird es keine richtige Abfrage erstellen.

+3

Plus 1 - Dies ist die richtige Antwort. Ich werde meine löschen, sobald das OP diese Antwort akzeptiert. –

+0

Sieht wieder gut aus, außer die Bindung stimmt nicht ganz. Ich finde, dass der Parameter $ this -> ticker in die Abfrage ohne Anführungszeichen eingegeben wird, was zu einem Fehler führt. Z.B. '... UND ticker = ukc0tr01 INDEX) ...' – harryg

+0

Das gleiche geschieht auch für das Datum: 'WHERE price_date <= 2014-07-31'. Warum keine Zitate um das Datum? – harryg