Reputation: 2067
I know title is really ridiculous. I couldn't find how I can describe this.
This is my table structure
This is a car rental webpage. What I’m doing is I’m trying to figure out if a car is reserved in particular “pickup_date“ and “dropoff_date”. I can get reserved cars with this query
SELECT
cars.model,
reservations.pickup_date,
reservations.dropoff_date,
reservations.car_id
FROM
cars
INNER JOIN reservations ON cars.car_id = reservations.car_id
WHERE
reservations.pickup_date <= '2012-04-08 10:50:26' OR
reservations.dropoff_date >= '2012-04-20 10:50:26'
However, there are some cars that are not reserved and they are not shown in this query, since I don’t have all car models in reservation. I have them in cars table.
The bottom line, I should eliminate the ones that I get from this query from the table that has all car models. Therefore, I will have cars which are not reserved + the ones that will be available after reserve dates.
It will get the results that I got from the query, and eliminate this results from cars table. After that It will show me.
I can do it with PHP. However, I want to learn if it is possible to do it with one query with mysql.
This is the solution that I came up with with the help of @cbuckley
SELECT
cars.*
FROM cars
LEFT JOIN (
SELECT
cars.car_id
FROM
cars
INNER JOIN reservations
ON cars.car_id = reservations.car_id
WHERE
(reservations.pickup_date <= '2012-04-08 10:50:26' AND reservations.dropoff_date >= '2012-04-20 10:50:26') OR
(reservations.pickup_date >= '2012-04-08 10:50:26' AND reservations.pickup_date <= '2012-04-20 10:50:26') OR
(reservations.dropoff_date <= '2012-04-20 10:50:26' AND reservations.dropoff_date >= '2012-04-08 10:50:26')
) AS reserved_cars
ON reserved_cars.car_id = cars.car_id
WHERE reserved_cars.car_id IS NULL;
Upvotes: 2
Views: 64
Reputation: 42468
You need to be careful distinguishing cars with no reservation at a given time and cars with a reservation at a time other than the given time. The former is what you're after and could be achieved with a WHERE NOT IN
clause. However as your cars and reservations system grows, this could become hideously slow. I would suggest the following:
SELECT
cars.*
FROM cars
LEFT JOIN (
SELECT
cars.car_id
FROM
cars
INNER JOIN reservations
ON cars.car_id = reservations.car_id
WHERE
reservations.pickup_date <= '2012-04-08 10:50:26' OR
reservations.dropoff_date >= '2012-04-20 10:50:26'
) AS reserved_cars
ON reserved_cars.car_id = cars.car_id
WHERE reserved_cars.car_id IS NULL;
The inner query is the one you specified to find all reserved cars. You then join that back to the cars
table to find all cars which are not returned by the inner query. This works because you perform a LEFT JOIN
to the subquery and only return rows which didn't have a match in the subquery.
EDIT: If you want the query to find all cars which are available for a given period, your inner query needs to search for reservations which start or end within that period. You would therefore use the following condition:
... WHERE
reservations.pickup_date BETWEEN '2012-04-08 10:50:26' AND '2012-04-20 10:50:26' OR
reservations.dropoff_date BETWEEN '2012-04-08 10:50:26' AND '2012-04-20 10:50:26'
Upvotes: 0
Reputation: 8461
Use Left Join rather than Inner join
SELECT
cars.model,
reservations.pickup_date,
reservations.dropoff_date,
reservations.car_id
FROM
cars
LEFT JOIN reservations ON cars.car_id = reservations.car_id
WHERE
reservations.pickup_date <= '2012-04-08 10:50:26' OR
reservations.dropoff_date >= '2012-04-20 10:50:26'
It will give you all the cars too who are not reserved yet
Upvotes: 1