fix(药分享): 商品清单去重改用代表行,修复 ONLY_FULL_GROUP_BY 报错

现象:小程序“药分享”页 onShow 抛
  TypeError: Cannot read properties of undefined (reading 'list')
根因在本接口:/yxe/yxe-share-detail/page?groupByProduct=true 返回
code=1 且不带 data,前端取 data.list 直接抛异常,中断整个 onShow。

原因:原 SQL 为 `SELECT a.* FROM yxe_share_detail a WHERE ... GROUP BY a.goods_name`。
MySQL 开启 ONLY_FULL_GROUP_BY 时,SELECT 列表中 a.* 的非分组列既不在
GROUP BY 内也不函数依赖于分组列,直接报
  Expression #1 of SELECT list is not in GROUP BY clause and contains
  nonaggregated column '...a.id' which is not functionally dependent on
  columns in GROUP BY clause
生产库恰好关闭了该 sql_mode 才长期未暴露,本地库(MySQL 9.7)已开启。

改法:取每个 goods_name 在**筛选结果集内**的最小 id 作为代表行,
语义与原 WHERE 之后 GROUP BY 一致。内层子查询重复同一套筛选条件,
否则按 province/city 过筛后该代表行可能不在结果集中,对应商品会整个消失。
未用窗口函数,不依赖 MySQL 8.0。

验证(本地库):
- groupByProduct=true          code=0,5 个去重商品(修复前 code=1)
- groupByProduct + city        count=3,内外层条件一致生效
- groupByProduct + goodsName   count=2
- 不带 groupByProduct          count=12,原有行为不变
This commit is contained in:
2026-10-12 14:49:30 +08:00
parent 1c431c6899
commit afa28827b6
@@ -2,7 +2,28 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gxwebsoft.yxe.mapper.YxeShareDetailMapper"> <mapper namespace="com.gxwebsoft.yxe.mapper.YxeShareDetailMapper">
<!-- 关联查询sql --> <!--
关联查询sql
【按商品去重(groupByProduct)为什么不能用 GROUP BY】
原先写成 `SELECT a.* FROM yxe_share_detail a WHERE ... GROUP BY a.goods_name`。
MySQL 开启 ONLY_FULL_GROUP_BY 时,SELECT 列表 a.* 中的非分组列既不在
GROUP BY 中、也不函数依赖于分组列,会直接抛:
Expression #1 of SELECT list is not in GROUP BY clause and contains
nonaggregated column '...a.id' which is not functionally dependent on
columns in GROUP BY clause
接口因此返回 code=1 且**不带 data**,前端 getProductList 里 `data.list`
就抛 "Cannot read properties of undefined (reading 'list')",
整个 onShow 中断,页面数据全部不渲染。
【现在的写法】
取每个 goods_name 在**筛选结果集内**的最小 id 作为代表行,语义与原先的
WHERE 之后 GROUP BY 完全一致(代表行只能从筛选后的行里产生)。
内层子查询必须重复同一套筛选条件:若只按整表取 MIN(id),当 province/city
过筛后该代表行可能不在结果集中,对应商品会整个消失。
用 MIN(id) + IN 而非窗口函数,是因为不依赖 MySQL 8.0。
-->
<sql id="selectSql"> <sql id="selectSql">
SELECT a.* SELECT a.*
FROM yxe_share_detail a FROM yxe_share_detail a
@@ -50,10 +71,58 @@
AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%')
) )
</if> </if>
<if test="param.groupByProduct != null">
AND a.id IN (
SELECT MIN(b.id)
FROM yxe_share_detail b
WHERE 1 = 1
<if test="param.id != null">
AND b.id = #{param.id}
</if>
<if test="param.shareId != null">
AND b.share_id = #{param.shareId}
</if>
<if test="param.province != null">
AND b.province = #{param.province}
</if>
<if test="param.city != null">
AND b.city = #{param.city}
</if>
<if test="param.goodsName != null">
AND b.goods_name LIKE CONCAT('%', #{param.goodsName}, '%')
</if>
<if test="param.spec != null">
AND b.spec LIKE CONCAT('%', #{param.spec}, '%')
</if>
<if test="param.num != null">
AND b.num = #{param.num}
</if>
<if test="param.sortNumber != null">
AND b.sort_number = #{param.sortNumber}
</if>
<if test="param.status != null">
AND b.status = #{param.status}
</if>
<if test="param.deleted != null">
AND b.deleted = #{param.deleted}
</if>
<if test="param.deleted == null">
AND b.deleted = 0
</if>
<if test="param.createTimeStart != null">
AND b.create_time &gt;= #{param.createTimeStart}
</if>
<if test="param.createTimeEnd != null">
AND b.create_time &lt;= #{param.createTimeEnd}
</if>
<if test="param.keywords != null">
AND (b.comments LIKE CONCAT('%', #{param.keywords}, '%')
)
</if>
GROUP BY b.goods_name
)
</if>
</where> </where>
<if test="param.groupByProduct != null">
GROUP BY a.goods_name
</if>
</sql> </sql>
<!-- 分页查询 --> <!-- 分页查询 -->