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

Laravel Eloquent:按关联价格对Product模型排序的问题

多价格关联产品的排序实现问题

数据表结构

pricing_types表

  • id
  • name(定价类型名称,如「个人用户」「企业用户」)
  • percent(价格系数,如100表示加价100%,30表示折扣70%)

product_prices表

  • id
  • value(基准价格)
  • pricing_type_id(关联pricing_types表)
  • product_id(关联products表)

products表

  • id
  • name(产品名称)
  • image(产品图片)

需求说明

每个产品对应多个不同群体的定价(通过product_prices关联不同pricing_types),需要按价格对产品进行排序,但尝试以下两种写法均未生效:

写法一(无效)

$q = Product::join('product_prices', function (JoinClause $join) {
    $join->on('product_prices.product_id', '=', 'products.id');
})->with(['category', 'prices', 'prices.pricingTypes'])->orderBy('product_prices.value', 'ASC')->simplePaginate(20)->withQueryString();

写法二(无效)

Product::with(['prices' => function ($q) {
    return $q->orderBy('value', 'ASC');
}], 'prices.pricingTypes')->simplePaginate(20)->withQueryString();

问题分析

  1. 写法一问题:直接join会产生重复的产品记录(一个产品对应多条price记录),分页时会把重复项计入总数,导致分页数据不准确;且排序是基于所有price的value,但产品重复展示,不符合需求。
  2. 写法二问题:with中的orderBy仅对关联的prices集合内部排序,不会改变Product模型本身的排序顺序,产品仍按默认规则(如id)排序,而非价格。

解决方案

根据实际需求选择以下方案:

方案1:按产品的最低价格排序

通过子查询为每个产品附加「最低价格」字段,再按该字段排序:

Product::with(['category', 'prices', 'prices.pricingTypes'])
    ->select('products.*')
    ->selectSub(function ($query) {
        $query->selectRaw('MIN(value)')
            ->from('product_prices')
            ->whereColumn('product_prices.product_id', 'products.id');
    }, 'min_price')
    ->orderBy('min_price', 'ASC')
    ->simplePaginate(20)
    ->withQueryString();

也可通过join+分组实现:

Product::join('product_prices', 'products.id', '=', 'product_prices.product_id')
    ->with(['category', 'prices', 'prices.pricingTypes'])
    ->select('products.*')
    ->selectRaw('MIN(product_prices.value) as min_price')
    ->groupBy('products.id')
    ->orderBy('min_price', 'ASC')
    ->simplePaginate(20)
    ->withQueryString();

方案2:按特定定价类型的价格排序

如果需要针对某类用户(如企业用户,假设pricing_type_id为2)的价格排序,可关联指定的price记录:

Product::leftJoin('product_prices', function ($join) {
    $join->on('products.id', '=', 'product_prices.product_id')
        ->where('product_prices.pricing_type_id', 2); // 替换为目标定价类型ID
})
->with(['category', 'prices', 'prices.pricingTypes'])
->select('products.*')
->orderBy('product_prices.value', 'ASC')
->simplePaginate(20)
->withQueryString();

注:若部分产品未设置该定价类型,leftJoin会保留这些产品,排序时未关联的price值为null,会排在最前或最后,可根据需求调整排序规则(如orderByRaw('product_prices.value IS NULL, product_prices.value ASC'))。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 20:43:38