Cómo seleccionar con combinaciones y sólo devolver las filas de una tabla?

Tengo una base de datos que se parece a esto: https://i.imgur.com/dwaqUF2.png

Quiero seleccionar todas las habitaciones que no tienen ninguna reserva para un determinado período de tiempo.

Aquí es lo que he intentado:

SELECT idRoom, type, beds FROM Room r
INNER JOIN Reservation_has_Room has on r.idRoom = has.Room_idRoom
INNER JOIN Rezervation re on has.Reservation_has_Room = re.idReservation
 WHERE (re.checkIn<'2019-06-04'
 AND re.checkOut<'2019-06-01') 
 or
(re.checkIn>'2019-06-04'
 AND re.CheckOut>'2019-06-01');

Pero esta secuencia de comandos devuelve una habitación cada vez que se encuentra una reserva que no es la superposición de la fecha.

2 Respuestas

  • Tim Biegeleisen
    4 de mayo de 2019

    Esta es la superposición de gama problema, y su WHERE cláusula debe ser:

    WHERE
        re.checkIn <= '2019-06-04' AND
        re.checkOut >= '2019-06-01'
    

    Su consulta completa:

    SELECT
        idRoom,
        type,
        beds
    FROM Room r
    INNER JOIN Reservation_has_Room has
        ON r.idRoom = has.Room_idRoom
    INNER JOIN Rezervation re
        ON has.Reservation_has_Room = re.idReservation
    WHERE
        re.checkIn <= '2019-06-04' AND
        re.checkOut >= '2019-06-01';
    
  • AlexYes
    4 de mayo de 2019

    Sí, lo es porque estás haciendo una combinación interna y filtro de las reservas. Lo que usted necesita está habitaciones left join de reservas en el período de tiempo en condiciones y, a continuación, filtro de unidades que no tienen ningún tipo de reservas se unió a:

    SELECT idRoom, type, beds 
    FROM Room r
    LEFT JOIN Reservation_has_Room has 
    ON r.idRoom = has.Room_idRoom
    LEFT JOIN Rezervation re 
    ON has.Reservation_has_Room = re.idReservation
    AND (
        re.checkIn <= '2019-06-01' AND re.checkOut >= '2019-06-04' -- (1)
        or re.checkIn between '2019-06-01' and '2019-06-04' -- (2)
        or re.checkOut between '2019-06-01' and '2019-06-04' -- (3)
    )
    WHERE re.checkIn is null -- filter out units that don't have matching reservations
    

    la condición de combinación de arriba tiene 3 casos:

    1) la superposición de las reservas 2) las reservas que empezar en algún lugar en el medio del período y al final algún tiempo después de 3) las reservas que se inicie algún tiempo antes y terminar en algún lugar en el medio del período

    La condición sugerida por Tim también podría funcionar. Pero el punto principal es cambiar a LEFT JOIN con filtro de rango en la condición de combinación y tiene WHERE re.checkIn is null

    Para hacer la solución más dinámico, se podría utilizar subconsultas para especificar el tiempo de los límites de una sola vez y la reutilización de estos valores en el filtro:

    WITH
     start_date as (select '2019-06-01'::date)
    ,end_date as (select '2019-06-04'::date)
    

    y tener esto como una condición de combinación:

    (
        re.checkIn <= (select * from start_date) AND re.checkOut >= (select * from end_date) -- (1)
        or re.checkIn between (select * from start_date) and (select * from end_date) -- (2)
        or re.checkOut between (select * from start_date) and (select * from end_date) -- (3)
    )