2014-11-21 28 views
12

Tôi đã truy vấn hùng biện sau (Đây là một phiên bản đơn giản của một truy vấn trong đó bao gồm nhiều where s và orWhere s do đó cách vòng xoay rõ ràng đi về việc này - lý thuyết là những gì quan trọng):Làm thế nào để tạo truy vấn con bằng cách sử dụng 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(); 

Như bạn có thể thấy I pluck ngày sớm nhất xảy ra vào hoặc sau start_date của tôi. Điều này dẫn đến một truy vấn riêng biệt đang chạy để có được ngày này sau đó được sử dụng như một tham số trong truy vấn chính. Có cách nào trong hùng hồn để nhúng các truy vấn với nhau để tạo thành một truy vấn phụ và do đó chỉ có 1 cuộc gọi cơ sở dữ liệu chứ không phải là 2?

Edit:

Theo @ câu trả lời Jarek của này là truy vấn của tôi:

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

Các orWhere khối đang gây ra tất cả các tham số trong truy vấn để đột nhiên trở nên không thể viện chứng. Ví dụ. WHERE price_date >= 2009-09-07. Khi tôi xóa orWheres truy vấn hoạt động tốt. Tại sao điều này?

Trả lời

16

Đây là cách bạn làm một subquery nơi:

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

Thật không may orWhere đòi hỏi phải được cung cấp một cách rõ ràng $operator, nếu không nó sẽ nâng cao một lỗi, vì vậy trong trường hợp của bạn:

$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: Bạn cần phải chỉ định from trong việc đóng cửa trong thực tế, nếu không nó sẽ không xây dựng truy vấn chính xác.

+3

Plus 1 - Đây là câu trả lời đúng. Tôi sẽ xóa của tôi ngay khi OP chấp nhận câu trả lời này. –

+0

Một lần nữa có vẻ tốt, ngoại trừ ràng buộc là không hoàn toàn đúng. Tôi thấy tham số '$ this-> ticker' được nhập vào truy vấn không được xác nhận dẫn đến lỗi. Ví dụ. '... AND ticker = ukc0tr01 INDEX) ...' – harryg

+0

Điều tương tự cũng xảy ra cho ngày: 'WHERE price_date <= 2014-07-31'. Tại sao không có dấu ngoặc kép nào trong ngày? – harryg

Các vấn đề liên quan