date - MySQL选择日期不在日期之间的行

标签 date mysql

我有一个预订系统,我需要从数据库中选择任何可用的房间。基本设置是:

table: room
columns: id, maxGuests

table: roombooking
columns: id, startDate, endDate

table: roombooking_room:
columns: id, room_id, roombooking_id

我需要选择适合要求的客人入住的房间,或者选择两个(或更多)房间来容纳客人(由 maxGuests 定义,显然首先使用最低/壁橱 maxGuests)

我可以遍历我的日期范围并使用这个 sql:

SELECT `id`
FROM `room` 
WHERE `id` NOT IN
(
    SELECT `roombooking_room`.`room_id`
    FROM `roombooking_room`, `roombooking`
    WHERE `roombooking`.`confirmed` =1
    AND DATE(%s) BETWEEN `roombooking`.`startDate` AND `roombooking`.`endDate`
)
AND `room`.`maxGuests`>=%d

其中 %$1 是循环日期,%2d 是要预订的客人数量。但是如果客人多于任何房间可以容纳的数量,这将返回 false,并且必须有更快的方法来执行此操作而不是使用 php 循环并运行查询?

这类似于我正在考虑的部分 sql:Getting Dates between a range of dates但是用 Mysql


解决方案,基于ircmaxwell的回答:

$query = sprintf(
        "SELECT `id`, `maxGuests`
        FROM `room`
        WHERE `id` NOT IN
        (
            SELECT `roombooking_room`.`room_id`
            FROM `roombooking_room`
            JOIN `roombooking` ON `roombooking_room`.`roombooking_id` = `roombooking`.`id`
            WHERE `roombooking`.`confirmed` =1
            AND (`roomBooking`.`startDate` > DATE(%s) OR `roomBooking`.`endDate` < DATE(%s))
        )
        AND `maxGuests` <= %d ORDER BY `maxGuests` DESC",
        $endDate->toString('yyyy-MM-dd'), $startDate->toString('yyyy-MM-dd'), $noGuests);
        $result = $db->query($query);
        $result = $result->fetchAll();

        $rooms = array();
        $guests = 0;
        foreach($result as $res) {
            if($guests >= $noGuests) break;
            $guests += (int)$res['maxGuests'];
            $rooms[] = $res['id'];
        }

最佳答案

假设您有兴趣将 @Guests@StartDate 放置到 @EndDate

SELECT DISTINCT r.id, 
FROM room r 
     LEFT JOIN roombooking_room rbr ON r.id = rbr.room_id
     LEFT JOIN roombooking ON rbr.roombooking_id = rb.id
WHERE COALESCE(@StartDate NOT BETWEEN rb.startDate AND rb.endDate, TRUE)
      AND COALESCE(@EndDate NOT BETWEEN rb.startDate AND rb.endDate, TRUE)
      AND @Guests < r.maxGuests

应该为您提供所有免费房间的列表,并且可以在给定时间段内容纳给定数量的客人。

注意事项
此查询仅适用于单个房间,如果您想查看多个房间,则需要对房间组合应用相同的条件。为此,您需要递归查询或一些帮助表。 此外,COALESCE 还负责处理 NULL——如果一个房间根本没有被预订,它就没有任何日期记录可以与之比较,因此它不会返回完全空闲的房间。如果 date1 或 date2 为 null,则 date1 和 date2 之间的日期将返回 NULL,并且 coalesce 会将其变为真(另一种方法是对完全空闲的房间执行 UNION;这可能会更快)。

有了多个房间,事情就会变得非常有趣。 这种情况是您问题的重要组成部分吗?您使用的是哪个数据库,即您可以访问递归查询吗?

编辑

正如我之前多次提到的,如果您想在所需的客人数量和房间之间找到最佳匹配,那么您寻找解决方案的方式(首先查看最大的空闲房间的贪婪算法)并不是最优的。

因此,如果您将 foreach 替换为

$bestCapacity = 0;
$bestSolution = array();

for ($i = 1; $i <= pow(2,sizeof($result))-1; $i++) {
    $solutionIdx = $i;
    $solutionGuests = 0;
    $solution = array();
    $j = 0;
    while ($solutionIdx > 0) :
        if ($solutionIdx % 2 == 1) {
            $solution[] = $result[$j]['id'];
            $solutionGuests += $result[$j]['maxGuests'];
        }
        $solutionIdx = intval($solutionIdx/2);
        $j++;
    endwhile;       
    if (($solutionGuests <= $bestCapacity || $bestCapacity == 0) && $solutionGuests >= $noGuests) {
        $bestCapacity = $solutionGuests;
        $bestSolution = $solution;
    }
}

print_r($bestSolution);
print_r($bestCapacity);

将遍历所有可能的组合并找到浪费最少空间的解决方案。

关于date - MySQL选择日期不在日期之间的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4165655/

相关文章:

python - 从 pandas 时间戳中删除日期部分的最快方法

javascript - 时刻js格式日期

mysql - 如何使用 MYSQL 将字符串拆分为表中的多行?

php - Laravel 中的四(或五)向表关系

mysql - 无法在 Mac OS X 上安装 mysql gem

php - php 中的表单

java - UNSIGNED BIGINT 的 jOOQ 函数生成生成 LONG 而不是 ULONG

r - 如何将特定(动态)列的日期增加一年?

MySQL 需要在 20 年到 90 年之间的列中添加随机日期

java - 将区域设置日期字符串转换为时间戳。 Java/安卓