2

I have three tables, one that lists regions, one that lists hotels and another that lists reservations. The hotels table has a foreign key for the regions table, to show which hotel is within which region, and the reservation table has a foreign key for the hotels table, to list reservations made against a hotel.

I'm trying to make it so that you can input a date, and the hotel isn't returned in the results, if that date is unavailable (though it's also possible to NOT input a date).

Currently, using the query listed at the bottom of the page, it lists out all the hotels even if they don't have a reservation against them. At this time, only one hotel has any reservations, and at that, there are two reservations in total. Before I included the 'DISTINCT' clause, to make it so that duplicate entries aren't listed, it would list out all hotels, including the one with reservations, except this one it would list TWICE as there were TWO reservations. Now, with the DISTINCT clause, it will only ever show one result, but it will ALWAYS show one result. It essentially says "This entry is in the time range specified, so we can't show that, but the other one isn't, so we will show it", even though it's the same hotel.

For reference, my query currently, using 2020-09-02 as the date to check availability for;

SELECT DISTINCT hotels.hotel_name FROM hotels

LEFT JOIN reservations ON hotels.id=reservations.hotel_id

LEFT JOIN regions ON hotels.region_id=regions.id WHERE Cast('2020-09-02' as DateTime) NOT BETWEEN reservations.start_date AND reservations.end_date OR reservations.start_date is NULL OR reservations.end_date is NULL;

Current results (Where date IS available);

Hotel 1 with two reservations
Hotel 2
Hotel 3
Hotel 4
Hotel 5

Current results (Where date ISN'T available);

Hotel 1 with two bookings
Hotel 2
Hotel 3
Hotel 4
Hotel 5

Current results (Where date is available, but 'DISTINCT' ISN'T used);

Hotel 1 with two bookings
Hotel 1 with two bookings
Hotel 2
Hotel 3
Hotel 4
Hotel 5

Current results (Where date isn't available, but 'DISTINCT' ISN'T used);

Hotel 1 with two bookings
Hotel 2
Hotel 3
Hotel 4
Hotel 5

Expected results (If chosen date ISN'T available);

Hotel 2
Hotel 3
Hotel 4
Hotel 5

Expected results (If chosen date IS available);

Hotel 1 with two bookings
Hotel 2
Hotel 3
Hotel 4
Hotel 5

Hopefully the expected results scenarios give an idea of what I'm going for.

Any help is appreciated.

EDIT: Link to a DBFiddle of the issue here: https://www.db-fiddle.com/f/n9Ew6nLCWQHDjYfxzp49xB/16

2
  • please make a complete minimal reproducible example
    – nbk
    Mar 14 at 21:58
  • Hi @nbk, sorry for the delay, but please find a link to a DB fiddle in the EDIT at the end of my question
    – Josh
    Mar 14 at 22:39
2

You need a DISTINCT because of the n:m relationships But the date selection i would write differently, so that all holtel.id should be excluded, which have a reservation on that day, so that it can't be choosen anymore

Schema (MySQL v5.7)

CREATE TABLE `reservations` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `hotel_id` int(10) unsigned DEFAULT NULL,
  `start_date` date DEFAULT NULL,
  `end_date` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;


insert  into `reservations`(`id`,`hotel_id`,`start_date`,`end_date`) values
    (1,1,'2020-08-26','2020-09-02'),
    (2,1,'2020-12-06','2020-12-13');


CREATE TABLE `regions` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `region_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

insert  into `regions`(`id`,`region_name`) values
    (1,'Region 1'),
    (2,'Region 2'),
    (3,'Region 3'),
    (4,'Region 4'),
    (5,'Region 5');


CREATE TABLE `hotels` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `region_id` int(10) unsigned DEFAULT NULL,
  `hotel_name` varchar(255) DEFAULT NULL,

  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

insert  into `hotels`(`id`,`region_id`,`hotel_name`) values
    (1,1,'Hotel 1'),
    (2,3,'Hotel 2'),
    (3,5,'Hotel 3'),
    (4,5,'Hotel 4'),
    (5,4,'Hotel 5');

Query #1

SELECT 
    DISTINCT hotels.hotel_name, regions.region_name
FROM
    hotels
        LEFT JOIN
    reservations ON hotels.id = reservations.hotel_id
        LEFT JOIN
    regions ON hotels.region_id = regions.id
WHERE
(reservations.start_date is NULL OR reservations.end_date is NULL)

        OR hotels.id NOT IN
        (SELECT h.id 
FROM hotels h
    INNER JOIN 
    reservations r ON h.id = r.hotel_id
WHERE
   CAST('2020-09-02' AS DATE) BETWEEN r.start_date AND r.end_date)  
;
hotel_name region_name
Hotel 2 Region 3
Hotel 3 Region 5
Hotel 4 Region 5
Hotel 5 Region 4

View on DB Fiddle

2
  • This works! Thank you very much! (Sorry in case you saw my last comment about it not working, I replaced the query in the linked fiddle with the query shown above, and then it worked as expected) Thank you :)
    – Josh
    Mar 14 at 23:23
  • i forgot to update the fiddle a, so i corrected it
    – nbk
    Mar 14 at 23:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.