MySQL查询问题:合并门店营业状态查询,解决跨天判断错误
解决跨天营业门店的单条查询状态判断问题
嘿,我来帮你搞定这个跨天营业门店的状态判断和重复输出问题!你的核心痛点是单条查询区分营业/停业,且每个门店只显示一次,之前的查询因为基于business_hour的每条记录判断,导致重复输出,而且停业的逻辑也不对——只要门店有任意一条营业时间满足当前营业,它就应该是OPEN状态,只有所有时间段都不满足才是CLOSED。
问题根源分析
- 你之前的查询从
business_hour表出发,每个门店有多条营业时间记录,所以会重复输出同一门店的状态; - 停业判断逻辑错误:你之前的查询会把不满足当前营业的单条记录标记为CLOSED,但实际上只要有一条记录满足营业,门店就是OPEN的。
解决方案:单条SQL实现门店状态唯一输出
我们可以从restaurant表出发,用EXISTS子查询判断每个门店是否存在有效的营业记录,再用CASE WHEN标记状态,同时通过GROUP BY确保每个门店只显示一次。另外,一定要用参数绑定避免SQL注入,别直接把变量拼进SQL里!
最终SQL查询(带PHP PDO实现)
// 获取当前星期几(和表中openday/closeday格式一致,比如'Monday') $today = date('l'); // 获取当前时间(比如'07:00:00') $timeNow = date('H:i:s'); // 准备SQL语句,用参数绑定 $stmt = $pdo->prepare(" SELECT r.id AS restaurantID, r.name, -- 替换成你restaurant表中的实际字段 CASE WHEN EXISTS ( SELECT 1 FROM business_hour bh WHERE bh.restaurantID = r.id AND ( -- 情况1:非跨天营业,当前时间在当天开门/关门区间内 (bh.openday = :today AND bh.closeday = :today AND bh.opentime <= :timeNow AND bh.closetime >= :timeNow) -- 情况2:跨天营业,今天是结束日,当前时间还没到关门时间 OR (bh.closeday = :today AND bh.closetime >= :timeNow) -- 情况3:跨天营业,今天是开始日,当前时间已经过了开门时间 OR (bh.openday = :today AND bh.opentime <= :timeNow) ) ) THEN 'OPEN' ELSE 'CLOSED' END AS status FROM restaurant r GROUP BY r.id, r.name "); // 绑定参数 $stmt->bindParam(':today', $today); $stmt->bindParam(':timeNow', $timeNow); $stmt->execute(); // 输出结果 while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { echo "{$row['restaurantID']} {$row['status']} - {$row['name']}<br>"; }
逻辑说明
- EXISTS子查询:检查当前门店是否存在任意一条满足营业条件的时间段,只要有一条符合,就标记为
OPEN; - GROUP BY r.id, r.name:确保每个门店只返回一条记录,避免重复;
- 参数绑定:用
:today和:timeNow代替直接拼接变量,彻底避免SQL注入风险。
可选扩展:显示当前营业时间段
如果你想给OPEN的门店显示当前的营业区间,可以调整SQL,添加子查询获取对应的时间段:
SELECT r.id AS restaurantID, r.name, CASE WHEN EXISTS ( SELECT 1 FROM business_hour bh WHERE bh.restaurantID = r.id AND ( (bh.openday = :today AND bh.closeday = :today AND bh.opentime <= :timeNow AND bh.closetime >= :timeNow) OR (bh.closeday = :today AND bh.closetime >= :timeNow) OR (bh.openday = :today AND bh.opentime <= :timeNow) ) ) THEN 'OPEN' ELSE 'CLOSED' END AS status, -- 获取当前有效的营业时间段(仅OPEN门店有值) (SELECT CONCAT(bh.openday, ' ', bh.opentime, ' -- ', bh.closeday, ' ', bh.closetime) FROM business_hour bh WHERE bh.restaurantID = r.id AND ( (bh.openday = :today AND bh.closeday = :today AND bh.opentime <= :timeNow AND bh.closetime >= :timeNow) OR (bh.closeday = :today AND bh.closetime >= :timeNow) OR (bh.openday = :today AND bh.opentime <= :timeNow) ) LIMIT 1) AS current_business_hours FROM restaurant r GROUP BY r.id, r.name;
这样输出时,OPEN的门店会显示当前的营业时段,CLOSED的门店该字段为NULL,你可以根据需求处理显示逻辑。
内容的提问来源于stack exchange,提问作者Rohis
相关产品推荐
相关产品推荐

