PHP使用单次MySQL查询提取两级数据并按顶层分类分组展示的实现问题
实现方案
你可以通过先分组再输出,或者循环时判断父分类切换的方式实现需求,两种方案都只需要单次SQL查询。
首先调整SQL的排序规则,保证同一父分类下的所有记录(父分类本身+子项)连续排列,且父分类排在子项前面:
SELECT * FROM menu WHERE org = ? ORDER BY COALESCE(NULLIF(parent, ''), mid) ASC, parent IS NOT NULL ASC
方案1:先组装分组数组再输出(推荐,可读性更高)
先遍历查询结果把父子项按分类组装,再遍历分组输出HTML:
<?php $org = "1"; $stmt = mysqli_prepare($db, "SELECT * FROM menu WHERE org = ? ORDER BY COALESCE(NULLIF(parent, ''), mid) ASC, parent IS NOT NULL ASC"); $stmt->bind_param("s", $org); mysqli_stmt_execute($stmt); $result = mysqli_stmt_get_result($stmt); // 组装分组数据 $groupedData = []; while ($row = mysqli_fetch_assoc($result)) { if (empty($row['parent'])) { // 父分类记录 $groupedData[$row['mid']]['category'] = $row; } else { // 子项记录,归属到对应父分类 $groupedData[$row['parent']]['items'][] = $row; } } // 输出HTML foreach ($groupedData as $group) { ?> <div class="category"><?php echo htmlspecialchars($group['category']['item']); ?><br> <?php foreach ($group['items'] as $item) { ?> <div class="item"><?php echo htmlspecialchars($item['item']); ?></div> <?php } ?> </div> <?php } ?>
方案2:单次循环直接输出(适合大数据量场景,节省内存)
通过变量记录当前父分类ID,遇到新父分类时关闭上一个分类容器再打开新容器:
<?php $org = "1"; $stmt = mysqli_prepare($db, "SELECT * FROM menu WHERE org = ? ORDER BY COALESCE(NULLIF(parent, ''), mid) ASC, parent IS NOT NULL ASC"); $stmt->bind_param("s", $org); mysqli_stmt_execute($stmt); $result = mysqli_stmt_get_result($stmt); $currentCatId = null; while ($row = mysqli_fetch_assoc($result)) { if (empty($row['parent'])) { // 遇到新的父分类,先关闭上一个分类的div if ($currentCatId !== null) { echo '</div>'; } // 输出新分类头部 echo '<div class="category">' . htmlspecialchars($row['item']) . '<br>'; $currentCatId = $row['mid']; } else { // 输出子项 echo '<div class="item">' . htmlspecialchars($row['item']) . '</div>'; } } // 循环结束后关闭最后一个分类容器 if ($currentCatId !== null) { echo '</div>'; } ?>
注意事项
- 输出内容统一加
htmlspecialchars转义,避免XSS注入风险 - 如果需要展示价格,直接在子项输出位置加
echo htmlspecialchars($item['price'])即可 - 方案1后续扩展更方便,比如添加分类判断、子项为空时的提示等逻辑成本更低
内容的提问来源于stack exchange,提问作者stefan999
相关产品推荐
相关产品推荐

