子查询在购物车合并计价中核心作用是按sku粒度独立计算每个商品的最终单价和可享优惠,避免join导致的漏匹配或重复计算;相关子查询确保动态、精准匹配最优优惠规则,并通过coalesce回退原价,联合索引与标量子查询协同保障正确性与性能。

子查询在购物车合并计价中的核心作用
直接用 JOIN 处理多商品、多优惠、多库存状态的购物车计价,极易漏掉未匹配的 SKU 或重复计算优惠。子查询在这里不是炫技,而是为了**按 SKU 粒度独立算出每个商品的最终单价和可享优惠**,再汇总——它天然隔离计算逻辑,避免 GROUP BY 错位或聚合干扰。
用相关子查询动态计算单个商品的折后价
常见错误是把优惠规则硬写进 SELECT,结果一加满减券就崩。正确做法是为每行 cart_item 启动一个相关子查询,查该商品当前可叠加的最优优惠:
SELECT
ci.sku_id,
ci.quantity,
(SELECT COALESCE(MIN(p.final_price), ci.original_price)
FROM price_rules p
WHERE p.sku_id = ci.sku_id
AND p.start_time = NOW()
AND ci.quantity >= p.min_quantity) AS final_unit_price
FROM cart_items ci
WHERE ci.cart_id = 'CART_123';
-
COALESCE(MIN(...), ci.original_price)确保没匹配到规则时回退原价 - 子查询里必须显式写
p.sku_id = ci.sku_id,否则变成非相关子查询,结果错乱 - MySQL 8.0+ 对这类相关子查询有较好优化;旧版本建议给
price_rules(sku_id, start_time, end_time, min_quantity)加联合索引
用标量子查询预聚合优惠券抵扣额度
用户可能领了多张券,但购物车只允许用一张。这时不能靠外层 JOIN 再 GROUP BY,会丢失“哪张券对哪个 SKU 最优”的上下文。改用标量子查询逐个算:
SELECT
ci.sku_id,
ci.quantity,
ci.final_unit_price,
(SELECT MAX(c.discount_amount)
FROM coupons c
WHERE c.user_id = ci.user_id
AND c.status = 'valid'
AND c.scope = 'all' -- 全场券
AND c.min_order_amount
- 内层
(SELECT SUM(...))是另一层相关子查询,必须写清楚ci2.cart_id = ci.cart_id - 如果券分品类(
scope = 'category'),子查询 WHERE 条件要加AND ci2.category_id = c.category_id - 注意
MAX()只取最高额,不等于实际能用——真实场景需额外判断券是否已被其他 SKU 占用,这通常得靠应用层协调
嵌套子查询处理库存与价格双重校验
前端显示的价格可能已过期,而库存又实时变动。合并计价前必须原子性校验“此刻能否以该价买该量”。这时候需要三层嵌套:最外层查购物车,中间层查库存水位,内层查有效价格规则:
SELECT
sku_id, quantity,
(SELECT final_price FROM (
SELECT p.final_price
FROM price_rules p
WHERE p.sku_id = outer_ci.sku_id
AND p.start_time = NOW()
AND outer_ci.quantity >= p.min_quantity
AND (SELECT stock_qty FROM inventory i WHERE i.sku_id = p.sku_id) >= outer_ci.quantity
ORDER BY p.priority DESC LIMIT 1
) AS valid_price) AS locked_price
FROM cart_items outer_ci
WHERE outer_ci.cart_id = 'CART_123';
-
inventory表的子查询必须放在WHERE条件里,不能放SELECT,否则 MySQL 5.7 会报错 “This version of MySQL doesn’t yet support ‘LIMIT & IN/ALL/ANY/SOME subquery’” -
ORDER BY p.priority DESC LIMIT 1是关键:同一 SKU 多条规则时,取优先级最高的那条,而不是随便一条 - 这种写法在高并发下仍有超卖风险,生产环境必须配合行锁或 Redis 预占库存
子查询嵌套越深,数据库优化器越难生成高效执行计划。超过三层嵌套且数据量大时,不如拆成临时表或应用层分步计算——别迷信“一条 SQL 解决所有问题”。










