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

求助:将Union查询转换为Laravel Eloquent查询语句

将复杂SQL转换为Laravel Eloquent查询

没问题,我帮你把这条包含Union合并、地理距离计算、多表关联和聚合统计的SQL转换成Laravel Eloquent查询,拆解成几个步骤来更清晰:

1. 构建Union合并的基础Pin查询

首先需要创建三个独立的Pin查询,分别对应不同订阅计划的限制条数,再用union方法合并它们:

// 构建Premium计划的Pin查询(取2条)
$premiumPins = \App\Models\Pin::where('subscription_plan', 'Premium')->limit(2);

// 构建Platinum计划的Pin查询(取1条)
$platinumPins = \App\Models\Pin::where('subscription_plan', 'Platinum')->limit(1);

// 构建Free计划的Pin查询(取10条)
$freePins = \App\Models\Pin::where('subscription_plan', 'Free')->limit(10);

// 合并三个查询,得到基础的Pin数据集
$basePinQuery = $premiumPins->union($platinumPins)->union($freePins);

2. 加入地理距离计算

接下来把合并后的查询作为子查询,同时添加你需要的地理距离计算逻辑(这里用的是英里计算,3959是地球半径英里值,要转公里的话换成6371):

// 定义距离计算的SQL片段
$distanceFormula = "(3959 * acos( cos( radians('27.788870') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('72.978920') ) + sin( radians('27.788870') ) * sin( radians( lat ) ) )) AS distance";

// 基于合并后的子查询创建主查询,绑定参数并添加距离计算
$query = \Illuminate\Support\Facades\DB::table(\Illuminate\Support\Facades\DB::raw("({$basePinQuery->toSql()}) as pin"))
    ->mergeBindings($basePinQuery) // 必须绑定子查询的参数,避免SQL注入
    ->selectRaw('pin.*, ' . $distanceFormula);

3. 关联其他表并添加聚合统计

然后左关联需要的pin_reviews、ads以及三级分类表,同时添加聚合统计字段:

$query->leftJoin('pin_reviews', 'pin_reviews.pin_id', '=', 'pin.id')
    ->leftJoin('ads', 'ads.pin_id', '=', 'pin.id')
    ->leftJoin('category as c', 'c.id', '=', 'ads.category_id')
    ->leftJoin('category as sc', 'sc.id', '=', 'ads.sub_category_id')
    ->leftJoin('category as ssc', 'ssc.id', '=', 'ads.sub_sub_category')
    ->selectRaw("
        pin_reviews.review,
        COUNT(pin_reviews.pin_id) as totalUserRating,
        SUM(pin_reviews.rating) / (COUNT(pin_reviews.rating) * 5) as rating,
        ads.product_name,
        ads.id as adId,
        ads.notes,
        ads.add_status,
        ads.description as adsDescription,
        c.name as catName,
        c.id as catId,
        sc.id as subcatId,
        sc.name as subName,
        ssc.id as SubsubId,
        ssc.name as subsubName
    ");

4. 添加过滤、分组、排序和分页

最后添加状态过滤、分组条件、距离筛选、排序和结果条数限制:

// 过滤状态为1的Pin
$query->where('pin.status', 1)
    // 按Pin的ID分组
    ->groupBy('pin.id')
    // 筛选距离小于380英里的结果
    ->having('distance', '<', 380)
    // 按距离升序排序
    ->orderBy('distance', 'asc')
    // 限制最终结果条数
    ->limit(15);

// 获取最终结果
$results = $query->get();

一些注意事项:

  • 确保你的Pin模型已经正确关联到pin数据表
  • mergeBindings方法非常重要,它能把子查询的参数绑定到主查询中,避免SQL注入问题
  • 如果你的Laravel开启了严格模式,可能需要调整config/database.php中的strict配置,或者确保所有非聚合字段都包含在groupBy中(原SQL也是按pin.id分组,所以当前写法是兼容的)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:54:35