PHP执行MySQL查询定义变量时出现意外变量语法错误
问题原因
mysqli::query()默认不支持单次执行多条SQL语句,你把多组SET、SELECT语句拼接在同一个字符串中调用该方法,会直接返回布尔值false,后续调用num_rows方法时就会抛出「在布尔值上调用成员函数」的致命错误。- SQL语句中日期属于字符串类型,直接拼接PHP变量未加单引号包裹,会触发SQL语法错误;同时未做参数转义,存在SQL注入风险。
- 最终返回的聚合统计结果只有
total_fl_built/total_qc_built/percentage三个字段,原代码循环读取date/hour/pnp_kdt等不存在的字段,会抛出未定义数组键的警告。 - PHP语法错误:
$total变量赋值的SQL字符串结尾没有添加语句结束分号;,会直接触发PHP解析错误。 - 逻辑漏洞:未做除零判断,当统计的总装机量为0时,百分比计算会触发MySQL除以零错误;另外当前SQL是精确匹配开始、结束两个单日的数值,和你要做日期范围入参的需求不匹配。
修复方案
把多语句查询合并为单条聚合SQL,用预处理语句绑定参数规避注入和语法问题,补充参数校验、除零兜底逻辑,移除不存在的字段读取逻辑。
<?php include 'action.php'; // 初始化并校验日期参数 $begindate = isset($_POST['start-date']) ? trim($_POST['start-date']) : ''; $enddate = isset($_POST['end-date']) ? trim($_POST['end-date']) : ''; // 按实际日期格式调整校验规则,这里默认是YYYY-MM-DD格式 if (empty($begindate) || empty($enddate) || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $begindate) || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $enddate)) { die("请提交合法的开始、结束日期"); } // 单条SQL完成所有统计,用IFNULL做空值、除零兜底 // 如果你需要统计【整个日期范围内】的总装机、总质检量,把WHERE条件改为 `date` BETWEEN ? AND ? 即可 $sql = "SELECT (SELECT IFNULL(SUM(`fl_built`), 0) FROM `records` WHERE `date` = ?) AS total_fl_built, (SELECT IFNULL(SUM(`fl_qc`), 0) FROM `records` WHERE `date` = ?) AS total_qc_built, ROUND( (SELECT IFNULL(SUM(`fl_qc`), 0) FROM `records` WHERE `date` = ?) / (SELECT IFNULL(SUM(`fl_built`), 1) FROM `records` WHERE `date` = ?) * 100 ) AS percentage "; // 预处理绑定参数,彻底避免引号、注入问题 $stmt = $conn->prepare($sql); // 按SQL中占位符顺序绑定4个字符串类型参数,若改成范围查询需同步调整参数顺序 $stmt->bind_param("ssss", $begindate, $enddate, $enddate, $begindate); $stmt->execute(); $result = $stmt->get_result(); echo "<table border='1' cellpadding='8'>"; echo "<tr><th>总装机量</th><th>总质检量</th><th>完成率(%)</th></tr>"; if ($result->num_rows > 0) { while ($row = $result->fetch_assoc()) { echo "<tr>"; echo "<td>{$row['total_fl_built']}</td>"; echo "<td>{$row['total_qc_built']}</td>"; echo "<td>{$row['percentage']}</td>"; echo "</tr>"; } } echo "</table>"; $stmt->close(); $conn->close(); ?>
注意事项
- 不推荐使用
multi_query()实现多语句执行,该方法需要手动逐个处理每个语句返回的结果集,代码冗余且SQL注入风险远高于预处理语句。 - 如果你的日期字段是DATETIME类型带时分秒,做范围查询时需要补充时间边界条件,避免漏算结束日期的数据。
- 代码中用IFNULL将无匹配数据时的统计值默认置为0,百分比计算时分母用1兜底,不会出现空值、除零报错。
内容的提问来源于stack exchange,提问作者user18495643
相关产品推荐
相关产品推荐

