嵌套While循环查询会议室数据:仅显示单个会议室名称问题排查
问题分析与解决方案
看起来你遇到的核心问题是HTML表格结构不完整导致的渲染异常,同时代码逻辑的排版问题也让浏览器无法正确解析所有会议室数据。浏览器对不规范的表格结构容错性有限,你的代码只输出了<td>单元格,却没有用<tr>(表格行)来包裹每一组数据,结果所有单元格被挤到了同一行,看起来就只有第一个会议室的名称能正常显示。
下面给你两种修正方案,分别对应不同的布局需求:
方案1:每行对应一个会议室的一个时段
如果希望每行显示「会议室名称 + 单个时段状态」,可以这样修改代码,补全完整的表格结构:
<table class="table table-bordered"> <thead> <tr> <th>会议室名称</th> <th>09:00 时段状态</th> </tr> </thead> <tbody> <?php $sql2 = $koneksi->query("SELECT id, nama_room FROM ruang_meeting ORDER BY id ASC"); while ($data = $sql2->fetch_assoc()) { $id = $data['id']; // 改用预处理语句避免SQL注入风险 $sql3 = $koneksi->prepare("SELECT * FROM tx_meetingroom WHERE id_ruang=?"); $sql3->bind_param("i", $id); $sql3->execute(); $result = $sql3->get_result(); // 处理该会议室无任何时段记录的情况 if ($result->num_rows === 0) { ?> <tr> <td><?php echo htmlspecialchars($data['nama_room']); ?></td> <td><a href='' class='btn btn-primary'><i class='fa fa-check'></i></a></td> </tr> <?php } else { while ($data2 = $result->fetch_assoc()) { ?> <tr> <td><?php echo htmlspecialchars($data['nama_room']); ?></td> <?php if ($data2['start'] === "09:00:00") { ?> <td><a href='' class='btn btn-danger' disabled><i class='fa fa-ban'></i></a></td> <?php } else { ?> <td><a href='' class='btn btn-primary'><i class='fa fa-check'></i></a></td> <?php } ?> </tr> <?php } } $sql3->close(); } ?> </tbody> </table>
方案2:每行对应一个会议室,显示所有时段状态
如果希望更清晰地查看单个会议室的所有时段可用性,可以用LEFT JOIN优化查询,把每个会议室的所有时段状态放在同一行:
<?php // 获取所有需要显示的时段(如果是固定时段,也可以直接手动定义数组) $timeSlotsQuery = $koneksi->query("SELECT DISTINCT start FROM tx_meetingroom ORDER BY start ASC"); $timeSlots = $timeSlotsQuery->fetch_all(MYSQLI_ASSOC); ?> <table class="table table-bordered"> <thead> <tr> <th>会议室名称</th> <?php foreach ($timeSlots as $slot) { ?> <th><?php echo substr($slot['start'], 0, 5); ?> 时段</th> <?php } ?> </tr> </thead> <tbody> <?php // 用JOIN一次性获取所有数据,减少数据库查询次数 $sql = $koneksi->query(" SELECT rm.id, rm.nama_room, tx.start FROM ruang_meeting rm LEFT JOIN tx_meetingroom tx ON rm.id = tx.id_ruang ORDER BY rm.id ASC, tx.start ASC "); $currentRoomId = null; $currentRoomName = ''; $occupiedSlots = []; while ($data = $sql->fetch_assoc()) { // 切换到新会议室时,先输出上一个会议室的状态行 if ($data['id'] !== $currentRoomId) { if ($currentRoomId !== null) { ?> <tr> <td><?php echo htmlspecialchars($currentRoomName); ?></td> <?php foreach ($timeSlots as $slot) { ?> <td> <?php if (in_array($slot['start'], $occupiedSlots)) { ?> <a href='' class='btn btn-danger' disabled><i class='fa fa-ban'></i></a> <?php } else { ?> <a href='' class='btn btn-primary'><i class='fa fa-check'></i></a> <?php } ?> </td> <?php } ?> </tr> <?php } // 初始化新会议室的状态 $currentRoomId = $data['id']; $currentRoomName = $data['nama_room']; $occupiedSlots = []; } // 记录当前会议室已被占用的时段 if (!empty($data['start'])) { $occupiedSlots[] = $data['start']; } } // 输出最后一个会议室的状态行 if ($currentRoomId !== null) { ?> <tr> <td><?php echo htmlspecialchars($currentRoomName); ?></td> <?php foreach ($timeSlots as $slot) { ?> <td> <?php if (in_array($slot['start'], $occupiedSlots)) { ?> <a href='' class='btn btn-danger' disabled><i class='fa fa-ban'></i></a> <?php } else { ?> <a href='' class='btn btn-primary'><i class='fa fa-check'></i></a> <?php } ?> </td> <?php } ?> </tr> <?php } ?> </tbody> </table>
额外优化建议
- 避免SQL注入:我在方案1中改用了预处理语句,直接拼接变量到SQL里会有安全风险,建议所有数据库操作都使用预处理。
- 转义输出内容:用
htmlspecialchars()转义会议室名称,避免XSS攻击和特殊字符渲染异常。 - 性能优化:方案2用
LEFT JOIN替代嵌套查询,减少了数据库请求次数,在数据量大时性能提升明显。
内容的提问来源于stack exchange,提问作者JuniorXcoder
相关产品推荐
相关产品推荐

