如何用MySQL消除嵌套循环?改写SQL后结果不符求解决
如何将嵌套循环的PHP+MySQL查询改写为正确的联表查询?
先帮你理清楚问题出在哪,再给出和原代码逻辑完全一致的改写方案。
首先拆解你的原代码逻辑:你先把inventory表中指定分类的所有商品查出来,然后对每个商品单独计算——它在未发货(is_dispatched=0)且单号类型是DC/D的出库单里的总待发数量。哪怕某个商品没有任何待发记录,原代码也会保留这个商品的记录,只是pending可能是null(或你后续处理为0)。
再看你改写的联表查询,有两个关键问题导致结果不一致:
- 用了隐式内连接(逗号分隔表),这会直接过滤掉没有对应出库记录的商品,而原代码里这些商品是会被保留的
GROUP BY里加了wn.withdraw_number,这会让同一个商品如果对应多个出库单时,拆分成多条记录返回,但原代码是每个商品只返回一条,总和所有出库单的数量
正确的联表查询SQL
下面是完全匹配原逻辑的改写,用左连接保证所有商品都被保留,同时正确计算待发数量:
SELECT i.item_code, i.item_category, i.item_description, i.quantity, i.reorder_point, COALESCE(SUM(w.quantity), 0) AS pending FROM inventory i LEFT JOIN withdrawals w ON i.item_code = w.item_code LEFT JOIN withdrawal_number wn ON w.withdraw_number = wn.withdraw_number AND wn.is_dispatched = 0 AND (wn.series_type = 'DC' OR wn.series_type = 'D') WHERE i.category = 'Store' GROUP BY i.item_code, i.item_category, i.item_description, i.quantity, i.reorder_point
关键细节说明
- LEFT JOIN的使用:用左连接替代内连接,确保
inventory里的所有商品不管有没有对应出库记录,都会出现在结果里 - 过滤条件放在ON子句:把
withdrawal_number的状态和类型条件放到JOIN的ON里,而不是WHERE,这样不会过滤掉没有匹配出库单的商品 - COALESCE处理null:当商品没有待发记录时,
SUM(w.quantity)会返回null,用COALESCE把它转换成0,和原代码中没有查询到结果的情况保持一致 - 正确的GROUP BY:只按商品的唯一标识和需要展示的字段分组,保证每个商品只返回一条记录,总和所有符合条件的待发数量
对应的PHP代码
把上面的SQL放到你的PHP里,用法和原代码类似:
$sqlcmd = "SELECT i.item_code, i.item_category, i.item_description, i.quantity, i.reorder_point, COALESCE(SUM(w.quantity), 0) AS pending FROM inventory i LEFT JOIN withdrawals w ON i.item_code = w.item_code LEFT JOIN withdrawal_number wn ON w.withdraw_number = wn.withdraw_number AND wn.is_dispatched = 0 AND (wn.series_type = 'DC' OR wn.series_type = 'D') WHERE i.category = 'Store' GROUP BY i.item_code, i.item_category, i.item_description, i.quantity, i.reorder_point"; $temp = mysql_query($sqlcmd); while ($value = mysql_fetch_array($temp)) { // 这里写你的业务处理逻辑,比如输出或存储数据 echo "商品编码:{$value['item_code']} | 库存数量:{$value['quantity']} | 待发数量:{$value['pending']}<br>"; }
另外提个小建议:mysql_*系列函数已经被PHP官方废弃了,建议后续升级成mysqli_*或者PDO,安全性和兼容性更好。
内容的提问来源于stack exchange,提问作者nwbie
相关产品推荐
相关产品推荐

