You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

数据库查询咨询:如何验证23号房间在指定日期区间的每日可用性

如何查询指定房间在日期区间内的每日可用性

嘿,我完全懂你的困扰——之前的SQL只检查有没有一个预订把整个日期区间都占了,但实际上你需要确认区间里的每一天都没被预订对吧?别担心,我来给你拆解正确的实现思路。

首先,我先假设你的预订表结构大概是这样的(如果实际结构不一样,你可以对应调整字段名):
room_bookings表包含:

  • room_id:房间编号
  • check_in_date:客人入住日期
  • check_out_date:客人退房日期(注意:通常这个日期是客人离开的当天,当天房间是可以重新预订的,所以判断冲突时要排除这个日期)

核心思路

要验证每日可用性,我们需要:

  1. 生成你指定的起止日期之间的所有日期(相当于把区间拆成单独的每一天)
  2. 检查这些日期中,有没有任何一天落在23号房间的某个预订时间段内
  3. 要么返回每一天的可用状态,要么直接判断整个区间是否完全可用

具体实现(分数据库示例)

1. 返回每日可用性详情

下面的查询会列出日期区间内的每一天,以及对应的可用状态:

PostgreSQL版本
WITH date_range AS (
    -- 生成起止日期之间的所有日期,替换成你的表单参数
    SELECT generate_series(:start_date::date, :end_date::date, '1 day'::interval) AS check_date
)
SELECT
    dr.check_date::date,
    -- 如果没有匹配到预订,说明当天可用
    CASE WHEN rb.room_id IS NULL THEN '可用' ELSE '不可用' END AS availability
FROM date_range dr
-- 左连接预订表,找出23号房间的冲突日期
LEFT JOIN room_bookings rb
    ON rb.room_id = 23
    AND dr.check_date >= rb.check_in_date
    AND dr.check_date < rb.check_out_date  -- 退房当天不算占用
ORDER BY dr.check_date;
MySQL 8.0+版本

MySQL需要用递归CTE生成日期序列:

WITH RECURSIVE date_range AS (
    SELECT CAST(:start_date AS DATE) AS check_date
    UNION ALL
    SELECT DATE_ADD(check_date, INTERVAL 1 DAY)
    FROM date_range
    WHERE check_date < CAST(:end_date AS DATE)
)
SELECT
    dr.check_date,
    CASE WHEN rb.room_id IS NULL THEN '可用' ELSE '不可用' END AS availability
FROM date_range dr
LEFT JOIN room_bookings rb
    ON rb.room_id = 23
    AND dr.check_date >= rb.check_in_date
    AND dr.check_date < rb.check_out_date
ORDER BY dr.check_date;
SQL Server版本
WITH date_range AS (
    SELECT CAST(:start_date AS DATE) AS check_date
    UNION ALL
    SELECT DATEADD(DAY, 1, check_date)
    FROM date_range
    WHERE check_date < CAST(:end_date AS DATE)
)
SELECT
    dr.check_date,
    CASE WHEN rb.room_id IS NULL THEN '可用' ELSE '不可用' END AS availability
FROM date_range dr
LEFT JOIN room_bookings rb
    ON rb.room_id = 23
    AND dr.check_date >= rb.check_in_date
    AND dr.check_date < rb.check_out_date
ORDER BY dr.check_date
OPTION (MAXRECURSION 0);  -- 解决递归深度限制

2. 直接判断整个区间是否完全可用

如果你只需要知道23号房间在整个区间内是否每天都可用,可以用这个更简洁的查询:

-- 这里以PostgreSQL为例,其他数据库只需要替换date_range的生成方式
WITH date_range AS (
    SELECT generate_series(:start_date::date, :end_date::date, '1 day'::interval) AS check_date
)
SELECT 
    NOT EXISTS (
        -- 检查是否存在任何一天被23号房间的预订占用
        SELECT 1
        FROM date_range dr
        JOIN room_bookings rb
            ON rb.room_id = 23
            AND dr.check_date >= rb.check_in_date
            AND dr.check_date < rb.check_out_date
    ) AS is_entire_period_available;

这个查询会返回true或false,true表示整个区间内房间每天都可用。

为什么之前的查询失效?

你之前的SQL应该是类似这样的:

SELECT * FROM room_bookings
WHERE room_id = 23
AND check_in_date <= :start_date
AND check_out_date >= :end_date;

这个查询只能查出有没有一个预订完全覆盖了你指定的区间,但如果区间内有几天被不同的预订占用,或者只有部分日期被占用,这个查询就查不出来了——而我们需要的是检查区间内的每一天都没有被任何预订占用。

注意事项

  • 记得用参数化查询替换:start_date和:end_date,避免SQL注入
  • 如果你的check_out_date定义是“客人占用房间的最后一天”(即退房当天房间也不可用),那把判断条件改成dr.check_date <= rb.check_out_date即可

内容的提问来源于stack exchange,提问作者Argoitz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:35:45