Yii2中如何在SELECT语句内比较两个子查询的求和结果?
解决Yii2主查询筛选子查询聚合结果的问题
问题分析
你当前的问题在于直接在WHERE子句中使用子查询聚合结果进行筛选,而WHERE是分组前执行的,无法正确引用分组后的聚合值;同时当无匹配数据时,sum()会返回null,导致比较逻辑失效。
解决方案
需要做两点核心修改:
- 用
COALESCE()处理聚合函数的null结果,转为0避免比较异常; - 使用
HAVING子句替代WHERE进行分组后的筛选(聚合结果的筛选必须在分组后执行)。
修改后的代码
1. 调整子查询,添加COALESCE处理空值
// 无匹配数据时返回0,避免null导致比较逻辑失效 $paidForOrder = (new Query())->select(['COALESCE(sum(amount*flow), 0)'])->from('moneyflow')->where('order_uid = i.uid'); $orderAmount = (new Query())->select(['COALESCE(sum(sale_price*qty*flow), 0)'])->from('salesflow')->where('order_uid = i.uid');
2. 主查询改用HAVING筛选聚合结果
$Query = (new Query()) ->select([ 'i.uid as uid', 'i.created as created', 'i.ordernum as ordernum', 'order_amount' => $orderAmount, 'paid_for_order' => $paidForOrder, ]) ->from('orders i') ->leftJoin('salesflow s','i.uid = s.order_uid') ->where(['i.type_id' => 2, 'i.customer_id' => $customer_id]) ->groupBy('i.uid') ->having(['<', 'paid_for_order', 'order_amount']) // 通过SELECT中的别名筛选 ->all();
备选方案(若数据库不支持HAVING用别名)
如果你的数据库不允许在HAVING中直接引用SELECT的别名,可以直接传入子查询对象:
->having(['<', $paidForOrder, $orderAmount])
或者直接写入完整SQL表达式:
->having('COALESCE((SELECT sum(amount*flow) FROM moneyflow WHERE order_uid = i.uid), 0) < COALESCE((SELECT sum(sale_price*qty*flow) FROM salesflow WHERE order_uid = i.uid), 0)')
内容的提问来源于stack exchange,提问作者Felix Abdullayev
相关产品推荐
相关产品推荐

