You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel whereHas结合havingRaw做最低房价筛选不生效问题

问题根源

原有scope代码无法生效有三个核心原因:

  • 在whereHas的关联查询中使用聚合函数MIN()时,没有按关联外键villa_id分组,MySQL会将所有匹配的预订方案行合并为单个聚合结果,无法按单个别墅维度计算最低房价
  • 直接将参数拼接进havingRaw存在SQL注入风险,且未做参数绑定,部分环境下会出现类型匹配错误
  • 若MySQL开启ONLY_FULL_GROUP_BY模式(5.7+默认开启),未分组的聚合查询会直接抛出SQL语法错误
可直接运行的修复方案

1. 修正Villa模型中的scope方法

/**
 * 筛选最低房价高于阈值的别墅
 */
public function scopeFilterMinRate($query, int $rate)
{
    return $query->whereHas('bookingPlans', function ($q) use ($rate) {
        $q->groupBy('villa_id')
          ->havingRaw('MIN(rate) > ?', [$rate]);
    });
}

/**
 * 筛选最低房价低于阈值的别墅
 */
public function scopeFilterMaxRate($query, int $rate)
{
    return $query->whereHas('bookingPlans', function ($q) use ($rate) {
        $q->groupBy('villa_id')
          ->havingRaw('MIN(rate) < ?', [$rate]);
    });
}

2. 修正控制器中的查询调用

原有控制器代码未对查询构建器实例重新赋值,部分场景下会出现筛选条件丢失的问题,调整为如下写法:

$villas = Villa::query()->active();

if ($request->leastRate >= 1) {
    $villas = $villas->filterMinRate($request->leastRate);
}

if ($request->maxRate >= 1) {
    $villas = $villas->filterMaxRate($request->maxRate);
}

// 后续获取结果逻辑 比如 $villas->get()
大数据量场景优化方案

如果booking_plans表数据量超过10万条,推荐使用子查询预聚合的方式替代whereHas联表分组查询,性能提升明显,scope写法如下:

public function scopeFilterMinRate($query, int $rate)
{
    return $query->whereRaw(
        '(SELECT MIN(rate) FROM booking_plans WHERE booking_plans.villa_id = villas.id) > ?',
        [$rate]
    );
}

public function scopeFilterMaxRate($query, int $rate)
{
    return $query->whereRaw(
        '(SELECT MIN(rate) FROM booking_plans WHERE booking_plans.villa_id = villas.id) < ?',
        [$rate]
    );
}

注意:该写法需要确保booking_plans表的villa_id字段已加索引,否则子查询性能会下降。

内容的提问来源于stack exchange,提问作者MilAD86

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 07:30:43