单表多字段排序异常:酒店价格降序排序逻辑修正诉求
解决方案:按酒店最大/最小价格正确排序
核心问题在于直接关联hotel_price表会返回每个酒店的多条价格记录,排序时无法自动按酒店维度取到对应极值(升序取最小、降序取最大)。双字段排序无效是因为关联后的数据是多对一结构,排序仅对所有价格记录生效,而非聚合后的酒店维度结果。
正确实现思路
需要先按酒店维度聚合出排序所需的价格极值,再基于这个聚合值完成排序。以下提供两种可行方案:
方案1:关联子查询获取聚合价格
通过子查询预计算每个酒店的目标价格,再关联主表进行排序:
// 重写排序类型判定方法 public function getOrderByType(): ?string { return in_array($this->fieldSort, ['price_asc', 'price_desc'], true) ? $this->fieldSort : null; }
$query = self::getActive(); $query->select([self::tableName() . '.*']); $sortType = $filter->getOrderByType(); if ($validate && $sortType) { // 确定聚合函数:升序取最小,降序取最大 $aggFunc = $sortType === 'price_asc' ? 'MIN' : 'MAX'; // 子查询生成每个酒店的目标价格数据集 $subQuery = (new \yii\db\Query()) ->select(['hotel_id', "{$aggFunc}(price) as target_price"]) ->from('hotel_price') ->groupBy('hotel_id'); // 关联聚合结果表 $query->leftJoin( ['price_agg' => $subQuery], self::tableName() . '.id = price_agg.hotel_id' ); // 按聚合后的价格排序 $query->orderBy([ 'price_agg.target_price' => $sortType === 'price_asc' ? SORT_ASC : SORT_DESC ]); }
方案2:聚合函数+分组排序
如果查询仅需酒店主表数据,可直接在排序中使用聚合函数,配合分组确保每个酒店仅返回一条记录:
// 修改排序字段生成逻辑 public function getOrderBy(): array { if (!in_array($this->fieldSort, ['price_asc', 'price_desc'], true)) { return []; } $aggFunc = $this->fieldSort === 'price_asc' ? 'MIN' : 'MAX'; $sortOrder = $this->fieldSort === 'price_desc' ? SORT_DESC : SORT_ASC; return [ "{$aggFunc}(hotel_price.price)" => $sortOrder ]; }
$query = self::getActive(); $query->select([self::tableName() . '.*']); if ($validate && !empty($filter->getOrderBy())) { $query->joinWith('hotelPrice'); // 必须按酒店ID分组,确保每个酒店仅返回一条主表记录 $query->groupBy(self::tableName() . '.id'); $query->orderBy($filter->getOrderBy()); }
原双字段排序无效原因
ORDER BY hotel_price.id DESC, hotel_price.price DESC 仅对所有关联后的价格记录排序,但框架(推测为Yii)在处理主表查询时会自动去重,最终排序依据的是关联后匹配到的第一条价格记录,而非酒店维度的最大价格,因此无法满足需求。
内容的提问来源于stack exchange,提问作者broken heart
相关产品推荐
相关产品推荐

