Laravel中如何实现关联存在时用关联字段、无关联用自身字段的orderBy查询
Laravel 产品关联价格统一排序实现方案
你不能直接在with预加载后对集合做排序,因为分页逻辑是在SQL查询阶段执行的,仅对当前页数据做集合排序会导致全局排序规则失效,必须在SQL层面生成统一的排序字段,实现方案如下:
方案1:左连接聚合实现(性能更优)
通过左连接关联产品类型表,聚合取关联类型的最低价格,和产品自身价格做合并后排序:
$products = Product::select('products.*') ->leftJoin('product_types', 'products.id', '=', 'product_types.product_id') // 存在关联类型时取最低类型价格,否则取产品自身价格作为排序字段 ->selectRaw('COALESCE(MIN(product_types.price), products.price) as sort_price') ->groupBy('products.id') ->orderBy('sort_price', 'asc') ->with('types') ->paginate(15);
注意:如果你的MySQL开启了
ONLY_FULL_GROUP_BY规则也无需担心,按产品主键id分组时,select中的products.*是合法的。
方案2:子查询实现(无GROUP BY冲突)
如果不想使用GROUP BY,可以用子查询获取关联类型的最低价格:
$products = Product::selectRaw('products.*, ( SELECT MIN(price) FROM product_types WHERE product_id = products.id ) as type_min_price') ->selectRaw('COALESCE(type_min_price, price) as sort_price') ->orderBy('sort_price', 'asc') ->with('types') ->paginate(15);
适配说明
如果业务要求取第一个关联类型的价格而非最低价格,只需要把上面的MIN(product_types.price)替换为对应逻辑即可,比如按类型ID升序取第一条的写法:
SELECT price FROM product_types WHERE product_id = products.id ORDER BY id ASC LIMIT 1
优化建议
给product_types表的product_id字段添加普通索引,可大幅提升关联查询性能。
内容的提问来源于stack exchange,提问作者Negar Javadzadeh
相关产品推荐
相关产品推荐

