使用mysqli与PHP实现动态数据透视表遇到问题求助
解决PHP + mysqli实现动态数据透视表的问题
我明白你现在的困境——MySQL里能跑的动态透视表SQL,放到PHP里用多查询就出问题,静态版本没问题但动态的卡壳了。咱们一步步拆解问题,修复代码:
核心问题分析
你的代码主要有两个关键问题:
- 多查询的结果集处理错误:
mysqli_multi_query执行后,前面的SET、SELECT INTO、PREPARE语句都不会返回数据行,只有EXECUTE stmt才会返回最终的透视表结果。你直接用第一个结果集去判断行数,自然拿不到数据。 - 字符串转义和调试缺失:SQL语句里的单引号嵌套容易出错,而且没有错误捕获,导致你不知道到底哪一步失败了。
修正后的代码
下面是调整后的完整代码,我加了详细的注释和错误处理:
function get_all_records() { $conn = getdb(); // 使用HEREDOC编写SQL,避免单引号转义混乱 $Sql = <<<SQL SET @sql = NULL; SELECT GROUP_CONCAT(DISTINCT CONCAT( 'MAX(IF(suo.date = ''', date, ''', suo.units_ordered, 0)) AS ', CONCAT('`',date,'`') )) INTO @sql FROM tbl_sku_units_order; SET @sql = CONCAT('SELECT ls.sku AS list_sku, COALESCE(MIN(suo.sku), ''NotSold'' ) AS sold_sku, ', @sql, ' , COALESCE( SUM(suo.units_ordered), 0 ) AS total_sold FROM tbl_list_sku AS ls LEFT JOIN tbl_sku_units_order AS suo ON suo.sku = ls.sku GROUP BY ls.sku ORDER BY total_sold DESC'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SQL; // 执行多查询 if (mysqli_multi_query($conn, $Sql)) { $result = null; // 遍历所有结果集,找到EXECUTE返回的那个 do { if ($currentResult = mysqli_store_result($conn)) { $result = $currentResult; mysqli_free_result($currentResult); } } while (mysqli_next_result($conn)); if ($result && mysqli_num_rows($result) > 0) { // 获取表头(动态生成的日期字段) $fields = mysqli_fetch_fields($result); echo "<table><thead><tr>"; foreach ($fields as $field) { echo "<th>" . htmlspecialchars($field->name) . "</th>"; } echo "</tr></thead><tbody>"; // 输出数据行 while ($row = mysqli_fetch_assoc($result)) { echo "<tr>"; foreach ($row as $value) { echo "<td>" . htmlspecialchars($value) . "</td>"; } echo "</tr>"; } echo "</tbody></table></div>"; } else { echo "<p class='text-center'>You have no recent QTY Daily Inventory</p>"; } } else { // 调试用:输出SQL错误 echo "<p class='text-center'>SQL Error: " . mysqli_error($conn) . "</p>"; } mysqli_close($conn); }
关键改进点
- 结果集遍历:通过
do-while循环调用mysqli_next_result,跳过前面无数据的结果集,只保留EXECUTE返回的最终数据。 - HEREDOC语法:用HEREDOC写SQL,避免了单引号嵌套的转义问题,代码可读性更强。
- 动态表头和数据输出:不再硬编码字段名,而是通过
mysqli_fetch_fields获取动态生成的日期字段,确保所有列都能正确显示。 - 错误处理:添加了
mysqli_error输出,方便你调试时查看具体的SQL错误。 - 安全处理:用
htmlspecialchars转义输出内容,防止XSS攻击。
额外调试建议
如果还是有问题,可以先把生成的@sql变量打印出来,看看最终拼接的SQL是否正确:
// 在EXECUTE stmt之前添加这行SQL $Sql .= "SELECT @sql;";
然后在遍历结果集的时候,把@sql的内容输出,复制到MySQL Workbench里执行,验证SQL本身是否正确。
内容的提问来源于stack exchange,提问作者Steven Smith
相关产品推荐
相关产品推荐

