2014-11-21 17 views
12

Ho la seguente domanda Eloquente (Questa è una versione semplificata di una query che consiste di più where s e orWhere s da qui il modo indiretto apparente di andare su questo - la teoria è quello che è importante):Come creare una sottoquery usando 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(); 

Come si può vedere I pluck la prima data che si verifica su o dopo il mio start_date. Ciò comporta l'esecuzione di una query separata per ottenere questa data che viene quindi utilizzata come parametro nella query principale. C'è un modo eloquente per incorporare le query insieme per formare una sottoquery e quindi solo 1 chiamata al database piuttosto che 2?

Edit:

Come da @ risposta di Jarek questa è la mia domanda:

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

I orWhere blocchi stanno causando tutti i parametri della query di diventare improvvisamente non quotate. Per esempio. WHERE price_date >= 2009-09-07. Quando rimuovo lo orWheres, la query funziona correttamente. Perchè è questo?

risposta

16

Questo è come si fa una sottoquery dove:

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

Purtroppo orWhere richiede esplicitamente prevista $operator, altrimenti si genera un errore, così nel tuo caso:

$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: È necessario specificare from nella chiusura, altrimenti non creerà la query corretta.

+3

Più 1 - Questa è la risposta corretta. Cancellerò il mio non appena l'OP accetta questa risposta. –

+0

Anche in questo caso sembra buono, tranne che il binding non è corretto. Trovo che il parametro '$ this-> ticker' sia inserito nella query non quotata risultante in un errore. Per esempio. '... AND ticker = ukc0tr01 INDEX) ...' – harryg

+0

Lo stesso vale anche per la data: 'WHERE price_date <= 2014-07-31'. Perché nessuna citazione intorno alla data? – harryg

Problemi correlati