SNaRe
SNaRe

Reputation: 2067

How to eliminate results from a table to another table?

I know title is really ridiculous. I couldn't find how I can describe this.

This is my table structure enter image description here

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

Answers (2)

cmbuckley
cmbuckley

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

Moyed Ansari
Moyed Ansari

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

Related Questions