J'ai la requête Eloquent suivante (Il s'agit d'une version simplifiée d'une requête qui se compose de plus de where
s et orWhere
s d'où la façon apparente de contourner cela - la théorie est ce qui est important):
$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();
Comme vous pouvez le voir, je pluck
la première date qui se produit le ou après mon start_date
. Il en résulte une requête distincte exécutée pour obtenir cette date qui est ensuite utilisée comme paramètre dans la requête principale. Existe-t-il un moyen éloquent d'incorporer les requêtes ensemble pour former une sous-requête et donc seulement 1 appel de base de données au lieu de 2?
Modifier:
Selon la réponse de @ Jarek, voici ma requête:
$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();
Les blocs orWhere
provoquent la disparition soudaine de tous les paramètres de la requête. Par exemple. WHERE
price_date>= 2009-09-07
. Lorsque je supprime le orWheres
, la requête fonctionne correctement. Pourquoi est-ce?
Voici comment vous effectuez une sous-requête où:
$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);
});
Malheureusement orWhere
nécessite explicitement fourni $operator
, sinon cela générera une erreur, donc dans votre cas:
$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: Vous devez spécifier from
dans la fermeture en fait, sinon il ne construira pas la requête correcte.