求助:将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
相关产品推荐
相关产品推荐

