使用while循环对比数据库值:PHP展示MySQL员工排班数据异常排查
解决MySQL员工排班日期匹配的PHP循环问题
首先得说,你遇到的问题核心应该是没有把数据库里的员工排班数据先按日期分组,而是直接在日期循环里硬套查询/结果遍历,导致要么结果集被提前耗尽,要么逻辑根本没关联起来。
先理清楚正确的思路:
- 第一步:先从数据库把当月所有员工的上班记录查出来,整理成「日期→员工列表」的关联数组,这样后续遍历日期的时候能直接快速匹配。
- 第二步:生成当前月份的所有日期,然后逐个日期去上面的数组里找对应的员工,按要求格式输出。
具体实现步骤&代码示例
1. 先获取并整理数据库中的排班数据
假设你的表结构是staff_schedule,字段是name(员工姓名)、work_date(上班日期,格式比如2024-02-01)。
<?php // 连接数据库(这里用PDO示例,你也可以用mysqli,逻辑一致) $pdo = new PDO('mysql:host=localhost;dbname=your_db;charset=utf8', 'username', 'password'); // 获取当前月份的起始和结束日期,避免硬写31天(不同月份天数不同) $currentMonthStart = date('Y-m-01'); $currentMonthEnd = date('Y-m-t'); // t代表当月最后一天的日期数字 // 查询当月所有排班记录 $stmt = $pdo->prepare("SELECT name, DATE_FORMAT(work_date, '%d') AS day FROM staff_schedule WHERE work_date BETWEEN ? AND ?"); $stmt->execute([$currentMonthStart, $currentMonthEnd]); $schedules = $stmt->fetchAll(PDO::FETCH_ASSOC); // 整理成「日期→员工列表」的数组 $dateStaffMap = []; foreach ($schedules as $item) { $day = (int)$item['day']; // 转成数字日期,比如1、2、3... if (!isset($dateStaffMap[$day])) { $dateStaffMap[$day] = []; } $dateStaffMap[$day][] = $item['name']; } ?>
2. 遍历当月所有日期并输出结果
<?php // 获取当月的总天数 $totalDays = date('t'); echo '<p>' . date('F') . ':</p>'; // 输出月份,比如February // 先把有员工的日期组整理出来,避免逐个日期输出(像你示例里的“1、2、3日 - John Wick”这种分组) $groupedResult = []; $currentGroup = []; $currentStaff = null; for ($day = 1; $day <= $totalDays; $day++) { $staff = isset($dateStaffMap[$day]) ? implode(', ', $dateStaffMap[$day]) : null; // 分组逻辑:如果当前日期的员工和上一个相同,就加入同一组 if ($staff === $currentStaff && $staff !== null) { $currentGroup[] = $day; } else { // 先把上一组输出(如果有的话) if (!empty($currentGroup) && $currentStaff !== null) { $groupedResult[] = [ 'days' => $currentGroup, 'staff' => $currentStaff ]; } // 开始新组 $currentGroup = $staff !== null ? [$day] : []; $currentStaff = $staff; } } // 处理最后一组 if (!empty($currentGroup) && $currentStaff !== null) { $groupedResult[] = [ 'days' => $currentGroup, 'staff' => $currentStaff ]; } // 输出最终结果 foreach ($groupedResult as $group) { // 处理日期格式:连续的日期用“-”,不连续用“、” $dayStr = ''; $prevDay = null; $tempRange = []; foreach ($group['days'] as $d) { if ($prevDay === null || $d === $prevDay + 1) { $tempRange[] = $d; } else { if (count($tempRange) > 1) { $dayStr .= reset($tempRange) . '-' . end($tempRange) . '、'; } else { $dayStr .= reset($tempRange) . '、'; } $tempRange = [$d]; } $prevDay = $d; } // 处理最后一个tempRange if (count($tempRange) > 1) { $dayStr .= reset($tempRange) . '-' . end($tempRange); } else { $dayStr .= reset($tempRange); } echo "<p>{$dayStr}日 - {$group['staff']}</p>"; } ?>
为什么你的原代码会出问题?
我猜你原来的代码大概是这样的逻辑:
// 错误示例 for ($n = 1; $n < 31; $n++) { echo $n . '日:'; // 这里重新查询或者直接遍历之前的结果集,但结果集已经被fetch完了 while ($row = $result->fetch()) { echo $row['name']; } echo '<br>'; }
这种写法的问题是:第一次循环的时候就把数据库结果集的所有行都fetch完了,后面的循环里fetch()就返回false,自然看不到员工数据;而去掉日期循环的话,能一次性把所有结果都输出,就是因为只遍历了一次结果集。
所以核心是先把所有数据拿到并整理成便于匹配的结构,再去遍历日期,而不是反过来在日期循环里反复操作结果集。
内容的提问来源于stack exchange,提问作者Polonio
相关产品推荐
相关产品推荐

