Reputation:
I have two tables (1. orders and 2. cars):
Cars
Orders
I'm trying to find all cars that are available at a given date. In this case I want to find all available cars between 2016-05-03 and 2016-05-05. I check for cars that are NOT BETWEEN
said date or cars that have not been registered in an order yet (orders.car_id IS NULL
). Here is the query:
SELECT destination, COUNT(destination) AS 'available cars'
FROM cars
LEFT JOIN orders ON cars.id = orders.car_id
WHERE (orders.car_id IS NULL
OR (
date_to NOT BETWEEN '2016-05-03' AND '2016-05-05'
AND date_from NOT BETWEEN '2016-05-03' AND '2016-05-05'
)
)
AND destination = 'Kristiansand' GROUP BY destination
The problem is with the Audi A1 with id = 8. As you can see, it is registered on two appointments, one from 2016-05-03
to 2016-05-05
and one from 2016-04-29
to 2016-04-30
.
Since the second pair of dates at the end of April are NOT BETWEEN
the given dates in the query, the A1 is an available car which is far from true.
I'm trying to fetch all cars available for rental outside of the given dates in Kristiansand.
Upvotes: 0
Views: 109
Reputation: 1966
This is correct, because of join you have theoretically you have 2 different AUDIs in the result set. I can suggest to use BETWEEN
instead of NOT BETWEEN
, get the ordered cars, and exclude them from cars table using statement NOT IN
with subquery, example below.
SELECT destination, COUNT(destination) AS 'available cars'
FROM cars
WHERE cars.id NOT IN (
SELECT DISTINCT car_id FROM orders WHERE
date_to BETWEEN '2016-05-03' AND '2016-05-05'
AND date_from BETWEEN '2016-05-03' AND '2016-05-05'
)
NOTE: This query not tested, we can do it if you provide SQLFiddle or something like that.
P.S. There are more optimal ways to do the same, with NOT EXISTS
statement or you can use JOIN
with subquery.
Upvotes: 0
Reputation: 6202
Let's say you have 2 periods T1 and T2 to check to see if they overlap you do this check (T1.start <= T2.end) AND (T1.end >= T2.start).
so try this below query, (it checks and makes sure that there doesn't exist an order of the same car that overlap the specified period
SET @startdate = '2016-05-03',@enddate = '2016-05-05';
SELECT c.destination,COUNT(c.destination) as available_cars
FROM cars c
WHERE NOT EXISTS (SELECT 1
FROM orders o
WHERE o.car_id = c.id
AND o.date_from <= @enddate
AND o.date_to >= @startdate)
AND c.destination = 'Kristiansand'
GROUP BY c.destination
http://sqlfiddle.com/#!9/9340e3/4
You can remove the SET statement and hardcode in your @enddate and @startdate
Upvotes: 0
Reputation: 133
I think it would be easier to find which cars are not available and then exclude them from the list. Something like this:
SELECT destination, COUNT(destination) AS 'available cars'
FROM cars
LEFT JOIN orders ON cars.id = orders.car_id
AND (date_to BETWEEN '2016-05-03' AND '2016-05-05'
OR date_from BETWEEN '2016-05-03' AND '2016-05-05')
WHERE orders.car_id IS NULL
AND destination = 'Kristiansand' GROUP BY destination
Upvotes: 0
Reputation: 1553
Change your thinking from exclusionary:
date_to NOT BETWEEN '2016-05-03' AND '2016-05-05'
AND date_from NOT BETWEEN '2016-05-03' AND '2016-05-05'
to inclusionary:
(date_from < '2016-05-03' AND date_to < '2016-05-05') OR
(date_from > '2016-05-03' AND date_to > '2016-05-05')
Upvotes: 0