【问题标题】:How to check if a booking exists within the time frame?如何检查在时间范围内是否存在预订?
【发布时间】:2016-07-19 21:07:48
【问题描述】:

我正在开发一个会议室预订系统,我无法确定是否在设定的时间范围内占用了一个房间,我正在使用当前的日期格式并将类型设置为 DATETIME 在表格中:@ 987654322@

这是我当前的代码:

//Function to check if a booking exists:
function bookingExist($DateStart, $DateEnd, $RoomNo) {
    global $DB;

    $sql = "SELECT * FROM bookings WHERE date_start = :dateStart AND date_end = :dateEnd AND room_no = :roomNo";
    $Q = $DB->prepare($sql);
    $Q->bindParam(':dateStart', $DateStart);
    $Q->bindParam(':dateEnd', $DateEnd);
    $Q->bindParam(':roomNo', $RoomNo);
    $Q->execute();

    if ($Q->rowCount()) {
        //A record exists...
        return true;
    } else {
        //no record exists
        return false;
    }
}

有没有办法在 sql 查询中做到这一点?

示例:房间 A 在 2016 年 3 月 31 日 15:00:00 和 2016 年 3 月 31 日 17:30:00 之间预订,然后用户尝试为 2016 年 3 月 31 日 16 日的房间 A 创建新预订: 30:00 - 2016-03-31 17:00:00 和 thsi 应该返回 1 记录,因为有预订

【问题讨论】:

  • 房间是从日期和时间 A 到日期和时间 B。因此,如果您的新时间范围的开始或结束时间介于 A 和 B 之间。这就是您在 SQL 中所需要的吗?
  • @Renan 这里是一个例子:房间 A 是在 2016-03-31 15:00:00 和 2016-03-31 17:30:00 之间预订的,然后用户尝试为房间 A 为 2016-03-31 16:30:00 - 2016-03-31 17:00:00 并且应该返回 1 记录,因为有预订
  • 查看我的更新答案。

标签: php mysql datetime pdo


【解决方案1】:

插入前检查

INSERT INTO .... SELECT .. WHERE NOT EXISTS (SELECT ...)

案例

[booking1 10/7/21 11:00 - 11:30]
[---新--- 10/7/21 11:30 - 11:20]
[预订2 10/7/21 12:00 - 12:30]

如果预订不存在,您可以使用以下语法插入预订:

-- new booking [b1][new][b2]
SET @s = '2021-07-10 11:30:00';
SET @e = '2021-07-10 12:00:00';

INSERT INTO Appointments
        (col1, col2, starts, ends) 
    SELECT 'some data', 'some data', @s, @e
    WHERE NOT EXISTS
        (SELECT id FROM Appointments -- search for collision points
        WHERE 
            ((starts <= @s AND @s < ends)
            OR (starts < @e AND @e <= ends)
            OR (@s <= starts AND starts < @e)
            ))
        AND (1=1) -- some other conditions
;

如果WHERE NOT EXISTS (SELECT...) 中没有数据返回,则INSERT 将继续执行。如果SELECT 返回至少一行,INSERT 将不会被执行。

以上示例允许预订开始和结束与新预订重叠。请注意,新预订从 11:30 开始。同时在 11:30 结束预订,这已经在我们的虚构数据库中。同样适用于新预订结束的时间 - 它也与预订 nr 2 的开始重叠,这没关系。上面的查询适用于这种情况。如果您改用 BETWEEN,则不会涵盖这种情况。

在大多数情况下,这会产生意想不到的结果:

WHERE NOT EXISTS 
(SELECT id FROM your_table
    WHERE 
        ((@s BETWEEN starts AND ends
            OR @e BETWEEN starts AND ends
            OR starts BETWEEN @s AND @e))
        AND (1=1)) -- replace (1=1) with other mandatory conditions
    LIMIT 1; 

这将产生正确的结果:

WHERE NOT EXISTS
(SELECT id FROM your_table
    WHERE 
        ((starts <= @s AND @s < ends)
            OR (starts < @e AND @e <= ends)
            OR (@s <= starts AND starts < @e))
        AND (1=1)) -- replace (1=1) with other mandatory conditions
    LIMIT 1; conditions

【讨论】:

    【解决方案2】:
    SELECT *
    FROM bookings
    WHERE
      (
        :dateStart BETWEEN date_start AND date_end
        OR :dateEnd BETWEEN date_start AND date_end
        OR date_start BETWEEN :dateStart AND :dateEnd
      )
      AND room_no = :roomNo
    

    如果在给定的时间跨度 :dateStart - :dateEnd 中没有预订房间,这将为您提供零行。 :dateStart BETWEEN date_start AND date_end 会在开始时间检查是否已经预订,:dateEnd BETWEEN date_start AND date_end 会在结束时间检查是否已经预订,最后一个 date_start BETWEEN :dateStart AND :dateEnd 也很重要,它会检查房间是否在中间预订(例如更短的时间)

    编辑:OR 次,没有 AND ;)

    EDIT2:要排除开始和结束时间,您必须扩展 BETWEEN 关键字并使关系仅为 &lt;

    SELECT *
    FROM bookings
    WHERE
      (
        (date_start < :dateStart AND :dateStart < date_end)
        OR (date_start < :dateEnd AND :dateEnd < date_end)
        OR (:dateStart < date_start AND date_start < :dateEnd)
      )
      AND room_no = :roomNo
    

    【讨论】:

    • :dateStart 应该是我的列名还是实际日期?
    • :dateStart 是您的变量 $DateStartdate_start 是您的列。在您的问题中,我只使用了与您相同的名称 sheme
    • 如果预订在今天 17:00 结束,我想预订 17:00 到 18:00 的会议怎么办?
    • 其实它会退回预定的房间。您可以将BETWEEN 替换为min &lt;= expr AND expr &lt;= max(例如date_start &lt;= :dateStart AND :dateStart &lt;= date_end),然后将&lt;= 强化为&lt;date_start &lt; :dateStart AND :dateStart &lt; date_end
    • 知道如何避免它吗?即从结束日期中删除 1 分钟并将其显示为结束日期 + 1 分钟?
    【解决方案3】:

    在 sql 查询中使用 BETWEEN 怎么样?您需要设置要检查的日期/时间参数(在给定示例中,这将是第二个用户请求的日期/时间)。

    $firstDate = //start of time period you are checking;
    $lastDate = //end of time period you are checking;
     $Q->bindParam(':firstDate ', $firstDate );
     $Q->bindParam(':lastDate ', $lastDate );
    
     $sql = "SELECT * FROM bookings WHERE :date_start BETWEEN :firstDate AND :lastDate  AND room_no = :roomNo";
    

    【讨论】:

    • 像这样:"SELECT * FROM bookings WHERE date_start BETWEEN :dateStart AND date_end BETWEEN :dateEnd AND room_no = :roomNo"
    • 运行查询时出现错误:#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '14:00:00 AND 2016-03-31 17:00:00 AND room_no = 1 LIMIT 0, 30' at line 1 查询:SELECT * FROM bookings WHERE date_start BETWEEN 2016-03-31 14:00:00 AND 2016-03-31 17:00:00 AND room_no = 1
    • 看起来您缺少 date_start 前面的冒号 - 应该是参数 ":date_start"
    • 它的日期,我以为我没有引用日期
    猜你喜欢
    • 2016-05-03
    • 1970-01-01
    • 2018-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多