PHP+MySQL实现HTML客户对账单累计余额计算异常排查
PHP 交易累计余额计算结果异常修复
核心错误点
- 加减逻辑完全错误:你的
total_running字段已经自带符号(支出为负、存入为正),不需要额外判断金额正负走不同计算分支。你当前对负值做$amount - $runningTotal的运算,是导致结果完全错乱的首要原因:
按你现有错误逻辑代入数值验证:假设初始值取到id=1的total_running为-980,第一条交易金额是-980,计算得-980 - (-980) = 0,第二条交易金额+980,计算得0 + 980 = 980,第三条交易金额+15000,计算得980 + 15000 = 15980,和你输出的错误结果完全吻合。 - 起始余额取值逻辑错误:硬编码取
id=1的记录作为起始余额完全不合理,该记录不一定属于当前查询的客户,也不一定在你选定的日期范围之前,会直接污染初始计算值。 - 日期查询语法错误:
BETWEEN条件后接的日期值不需要加%通配符(%是LIKE模糊查询的专用通配符),写在这里会导致日期匹配异常。 - 安全风险:SQL语句直接拼接PHP变量,存在SQL注入漏洞,建议改用预处理语句执行查询。
正确计算逻辑
累计余额(Running Total)的计算规则非常简单:
当前行累计余额 = 上一行累计余额 + 当前行交易金额(自带正负符号)
针对你的场景,选定日期范围的初始余额,应该是该客户在查询起始日期之前的最后一笔累计余额;如果没有更早的记录,初始余额直接设为0即可。按这个逻辑代入你的预期值验证:
- 初始余额为0,第一条交易为-980,累计值=0 + (-980) = -980
- 第二条交易为+980,累计值=-980 + 980 = 0
- 第三条交易为+15000,累计值=0 + 15000 = 15000
完全匹配你需要的预期结果。
修正后代码示例
<?php // 用预处理语句绑定参数,避免SQL注入 $stmt = $conn->prepare("SELECT * FROM statment_only WHERE customer = ? AND date BETWEEN ? AND ? ORDER BY date ASC, id ASC"); $stmt->bind_param("sss", $value, $date1, $date2); $stmt->execute(); $getTransactions = $stmt->get_result(); // 取查询日期范围之前该客户的余额作为初始值,无记录则初始为0 $stmtStart = $conn->prepare("SELECT total_running FROM statment_only WHERE customer = ? AND date < ? ORDER BY date DESC, id DESC LIMIT 1"); $stmtStart->bind_param("ss", $value, $date1); $stmtStart->execute(); $startRes = $stmtStart->get_result(); $runningTotal = 0; if ($startRow = $startRes->fetch_assoc()) { $runningTotal = $startRow['total_running']; } // 遍历计算累计值,不需要判断正负直接累加 while ($transaction = $getTransactions->fetch_assoc()) { $amount = $transaction['total_running']; $runningTotal += $amount; echo $runningTotal; } // 释放资源 $stmt->close(); $stmtStart->close(); ?>
注意:查询交易记录时必须加ORDER BY date ASC, id ASC排序,否则如果数据库返回的记录顺序错乱,累计值计算也会出错。
内容的提问来源于stack exchange,提问作者TanyaSmit
相关产品推荐
相关产品推荐

