Reputation: 31
I have hotel reservation system, when the user enters a new reservation date with the period I need to retrieve all the unreserved rooms,
reservations table contain room_id, startdate, period
I wrote this query, just need to simplify it
select *
from rooms
where id in (
select room_id
from reservations
where '2018-6-11' not BETWEEN date_at and date_add(date_at, INTERVAL period day)
and '2018-6-30' not between date_at and date_add(date_at, INTERVAL period day)
and date_at not between '2018-6-11' and '2018-6-30'
and date_add(date_at ,INTERVAL period day ) not between '2018-6-11' and '2018-6-30' )
or id not in (select room_id from reservations)
Upvotes: 1
Views: 170
Reputation: 3563
You don't need to do 2 IN
queries.
Since in your first IN
query you have only NOT
clauses, you can change those to NOT IN
and remove the NOT
s in the subquery.
That will also remove the second OR IN
.
select *
from rooms
where id not in (
select room_id
from reservations
where '2018-6-11' BETWEEN date_at and date_add(date_at, INTERVAL period day)
or '2018-6-30' between date_at and date_add(date_at, INTERVAL period day)
or date_at between '2018-6-11' and '2018-6-30'
or date_add(date_at ,INTERVAL period day ) between '2018-6-11' and '2018-6-30' ))
Basically this query translates to: Give me all rooms for which there is no reservation where my start- or end-date lies in between the reservation time.
EDIT:
Thanks to @vivek_23 I realized the query cannot be simplified in terms of the inner where conditions - nonetheless this version reduces the amount of queries to the database to 2.
Upvotes: 0
Reputation: 17805
Let's break this down into 2 sub problems.
In the query, I have assumed $start_date
and $end_date
are the PHP variables which have user selected values stored in them.
(select *
from rooms where room_id NOT IN (select room_id from reservations))
UNION
(select *
from rooms where room_id IN (
select room_id
from reservations
where $start_date not BETWEEN date_at and date_add(date_at, INTERVAL period day)
and $end_date not between date_at and date_add(date_at, INTERVAL period day)
and ($start_date > date_add(date_at, INTERVAL period day) OR $end_date < date_at)
))
Upvotes: 0
Reputation: 9886
What about converting IN
clause into equivalent joins? See below query if it works in your case:
SELECT *
FROM rooms rm
JOIN
(SELECT room_id rmid
FROM reservations
WHERE '2018-6-11' NOT BETWEEN date_at AND date_add(date_at, INTERVAL period DAY)
AND '2018-6-30' NOT BETWEEN date_at AND date_add(date_at, INTERVAL period DAY)
AND date_at NOT BETWEEN '2018-6-11' AND '2018-6-30'
AND date_add(date_at ,INTERVAL period DAY ) NOT BETWEEN '2018-6-11' AND '2018-6-30'
) tb1
ON rm.ID = tb.rmid
JOIN reservations rv
ON rm.ID <> rv.room_id;
Upvotes: 1