如何使用 Laravel Eloquent 创建子查询?

Posted

技术标签:

【中文标题】如何使用 Laravel Eloquent 创建子查询?【英文标题】:How to create a subquery using Laravel Eloquent? 【发布时间】:2015-01-19 19:04:26 【问题描述】:

我有以下 Eloquent 查询(这是查询的简化版本,由更多 wheres 和 orWheres 组成,因此显然是迂回的处理方式 - 理论才是重要的):

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

如您所见,我pluck 是在我的start_date 之后或之后发生的最早日期。这会导致运行单独的查询来获取此日期,然后将其用作主查询中的参数。有没有办法在 eloquent 中将查询嵌入在一起以形成一个子查询,因此只有 1 个数据库调用而不是 2 个?

编辑:

根据@Jarek 的回答,这是我的查询:

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

orWhere 块导致查询中的所有参数突然变为未引用。例如。 WHEREprice_date&gt;= 2009-09-07。当我删除 orWheres 时,查询工作正常。这是为什么呢?

【问题讨论】:

【参考方案1】:

这是你如何做一个子查询,其中:

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

不幸的是orWhere 需要明确提供$operator,否则会引发错误,所以在你的情况下:

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

编辑:实际上您需要在闭包中指定from,否则将无法构建正确的查询。

【讨论】:

加 1 - 这是正确答案。 OP 接受此答案后,我会立即删除我的。 再次看起来不错,除了绑定不太正确。我发现$this-&gt;ticker 参数被输入到未引用的查询中,导致错误。例如。 ...AND ticker = ukc0tr01 INDEX)... 日期也是如此:WHERE price_date &lt;= 2014-07-31。为什么日期前后没有引号? @harryg 不是真的,你一定做错了什么。它的工作原理与任何其他 where 相同。显示您拥有的代码。 仅仅拥有$q-&gt;orWhere('price_date', '=', function($q) use ($start_date)); 块会导致所有参数都没有被引用。我将在我的问题中发布整个雄辩的查询。

以上是关于如何使用 Laravel Eloquent 创建子查询?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用条件 Api 创建子查询

如何仅使用 css 为垂直导航栏创建子菜单

如何使用 Plotly Express 创建子图

如何在 Azure 存储位置创建子容器

基于布尔参数的 Laravel eloquent call realtionship

如何使用 matplotlib 创建子图的大图?