2014-11-21 16 views
12

Mam następujące zapytanie Eloquent (Jest to uproszczona wersja zapytania, który składa się z kilku where s oraz orWhere s stąd pozorne okrężną drogę pójścia na ten temat - w teorii jest to, co jest ważne):Jak utworzyć podzapytanie za pomocą Laravel Eoquent?

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

Jak widać I pluck najwcześniejszą datę, która pojawia się w dniu lub po mojej start_date. Powoduje to uruchomienie oddzielnej kwerendy w celu pobrania tej daty, która jest następnie używana jako parametr w głównym zapytaniu. Czy jest jakiś sposób na wymyślenie kwerendy razem, aby utworzyć podzapytanie, a zatem tylko 1 wywołanie bazy danych zamiast 2?

Edit:

Zgodnie @ odpowiedź Jarka to moje zapytanie:

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

W orWhere bloki są przyczyną wszystkich parametrów w zapytaniu do nagle stać cytowane. Na przykład. WHERE price_date >= 2009-09-07. Po usunięciu orWheres zapytanie działa poprawnie. Dlaczego to?

Odpowiedz

16

W ten sposób można zrobić podkwerenda gdzie:

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

Niestety orWhere wymaga wyraźnie przewidziane $operator, inaczej będzie podnieść błąd, więc w Twoim przypadku:

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

EDYCJA: Musisz określić from w zamknięciu w rzeczywistości, w przeciwnym razie nie będzie budować poprawne zapytanie.

+3

Plus 1 - To jest poprawna odpowiedź. Skasuję moje, gdy tylko PO przyjmie tę odpowiedź. –

+0

Ponownie wygląda dobrze, z wyjątkiem wiązania nie jest całkiem w porządku. Uważam, że parametr '$ this-> ticker' jest wprowadzany do zapytania niecałkowitego, co powoduje błąd. Na przykład. '... AND ticker = ukc0tr01 INDEX) ...' – harryg

+0

To samo dotyczy również daty: 'WHERE price_date <= 2014-07-31'. Dlaczego nie ma żadnych ofert w terminie? – harryg

Powiązane problemy