Я делаю систему бронирования для школьного проекта, но теперь я застрял.
У меня есть страница, где вы можете проверить, доступны ли номера для определенной категории номеров и даты.
Я знаю, что вы должны сделать внутреннее соединение. Я использовал Google, но я понятия не имею, как это сделать.
Это в моей базе данных отелей:
У меня есть стол для комнат:
TABLE `rooms` ( `roomNR` int(11) NOT NULL, `catagory` varchar(11) DEFAULT NULL, `picLocation` varchar(50) DEFAULT NULL, PRIMARY KEY (`roomNR`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
И у меня есть таблица бронирования, где хранятся все бронирования.
TABLE `reservation` (
`reservationID` int(11) unsigned NOT NULL AUTO_INCREMENT,
`userID` int(11) NOT NULL,
`roomNR` int(11) NOT NULL,
`start` date NOT NULL,
`end` date NOT NULL,
`price` float NOT NULL,
PRIMARY KEY (`reservationID`),
UNIQUE KEY `userID` (`userID`),
UNIQUE KEY `roomNR` (`roomNR`),
CONSTRAINT `reservation_ibfk_1` FOREIGN KEY (`roomNR`) REFERENCES `rooms` (`roomNR`),
CONSTRAINT `reservation_ibfk_2` FOREIGN KEY (`userID`) REFERENCES `users` (`userID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
Это форма, которую я использую:
<form action="" method="GET">
<div>
<label for="StartDate">From</label>
<input type="input" name="startDate" id="startDate" readonly=""> <label for="EndDate">Till</label> <input readonly="" type="input" name="endDate" id="endDate">
<label for="Catagory">Catagory:</label>
<select name="Catagory" id="Catagory">
<?php
$catagorys = DB::Getinstance()->query('SELECT * FROM catagory');
if ($catagorys->count()) {
foreach($catagorys->results() as $catagory){?>
<option value="<?php echo $catagory->name; ?>"><?php echo $catagory->name; ?></option>
<?php }
}
?>
</select> <input type="submit" value="get available rooms" class="btn btn-default">
</div></form>
Я надеюсь, что кто-то может помочь мне!
заранее спасибо!
— редактировать
Теперь, когда я смотрю на стол бронирования, не лучше ли будет хранить там также и категорию?
Это хорошая практика сначала упростить задачу в простые слова:
Выберите те номера, которые не упоминаются ни в одной записи бронирования и относятся к данной категории.
То, что вам на самом деле нужно здесь, это не INNER JOIN
, По крайней мере, не для этой части задачи. INNER JOIN
будет использоваться для «связи» с catagory
потом.
С помощью INNER JOIN
Здесь можно легко выбрать номера, которые уже зарезервированный: SELECT rooms.roomNR FROM rooms INNER JOIN reservation ON rooms.roomNR=reservation.roomNR WHERE catagory=$category_id
, Конечно, вы можете обработать эту информацию в PHP и использовать ее для довольно эффективного выбора оставшихся строк в таблице, но есть гораздо лучший способ.
Тебе необходимо подзапрос.
SELECT roomNR FROM `rooms` WHERE catagory=$category_id AND roomNR NOT IN (SELECT roomNR FROM `reservation`)
Это удачная особенность MySQL (или вообще SQL) в том, что синтаксис языка пытается максимально походить на английский письменный язык. Объяснение запроса: мы SELECT
roomNR
из тех rooms
которые не в SELECT roomNR FROM reservation
результат (или, проще говоря, reservation
Таблица).
Синтаксис и дополнительную информацию о подзапросах, пожалуйста, проверьте http://dev.mysql.com/doc/refman/5.1/en/subqueries.html.
Чтобы сделать этот шаг еще дальше и следовать своей бизнес-логике, можно сказать следующее:
Выберите те категории, в которых есть номера (по крайней мере, одна комната), не указанные в бронировании.
И это где вы можете реализовать INNER JOIN
, Перевод нашей проблемы в MySQL — при условии, что у вас есть id
а также name
поля для catagory
— у нас есть:
SELECT catagory.name FROM catagory INNER JOIN rooms ON catagory.id=rooms.catagory WHERE rooms.roomNR NOT IN (SELECT roomNR FROM reservation);
Если я не ошибаюсь, этот запрос должен запрашивать определенное имя категории, если хотя бы одна комната с таким идентификатором категории не указана в резервировании. Пожалуйста, проверьте, если это работает для вас, я не в такой среде, где я мог бы проверить это прямо сейчас.
РЕДАКТИРОВАТЬ: DISTINCT
ключевое слово
Если запрос каким-либо образом возвращает заданный catagory
несколько раз, пожалуйста, используйте DISTINCT
ключевое слово:
SELECT DISTINCT catagory.name FROM catagory ...
Для фильтрации по дате начала и окончания мы приходим к следующей проблеме:
Выберите те категории, в которых есть хотя бы одна комната, на которую нет ссылок
оговорки. Бронирование, которое выходит за рамки нашего времени (пример:
к моменту, когда следующий пользователь начинает
собственное бронирование) можно игнорировать, так как их номера свободны, поэтому они
больше не ограничивать наши возможности.
Переменные, используемые в следующем запросе:
$start_date = $_POST['startDate'];
$end_date = $_POST['endDate'];
Чтобы сделать это в SQL:
SELECT catagory.name FROM catagory INNER JOIN rooms ON catagory.id=rooms.catagory WHERE rooms.roomNR NOT IN (SELECT roomNR FROM reservation WHERE end<$start_date OR start>$end_date);
Как видите, мы используем обратную логику в подзапросе. Когда мы проверяем, зарезервирована ли данная комната (уже в reservation
), мы игнорируем те резервирования, которые не попадают под критерии времени: оно закончилось до начала следующего резервирования или началось до окончания следующего резервирования. Поэтому это не будет ограничивающим элементом для NOT IN
пункт.
Нет, вам также не нужно сохранять категорию в таблице бронирования, это будет избыточно.
Чтобы получить бронирование для этой категории и информацию о номере бронирования, вам понадобится запрос, подобный следующему:
SELECT rooms.roomNR, rooms.category, rooms.picLocation,
res.reservationID, res.userID, res.start, res.end, res.price
FROM rooms
INNER JOIN reservations res ON rooms.roomNR = res.roomNR
WHERE rooms.category = 'your_category_selection'