Tengo que asignar la reserva de boletos entre dos rangos de fechas, es decir, desde una fecha de inicio disponible y una fecha final (que no se asignó previamente). Para esto, necesito verificar en la base de datos si ya hubo alguna asignación entre estas fechas.
Por ejemplo, necesito asignar la reserva de boletos del 20/04/2017 al 25/04/2017. Antes de insertar este registro, necesito verificar si hubo alguna reserva realizada anteriormente entre la fecha de inicio 20/04/2017 y la fecha de finalización. 2017/04/25
Lo he intentado con la siguiente consulta. Pero no está dando el resultado correcto.
select "id" from "table" where "from_date" >= '2017-04-20' and "to_date" > '2017-04-20' and "from_date" < '2017-04-25' and "to_date" <= '2017-04-25'Su consulta no da el resultado esperado, porque solo prueba 1 de las 3 (o 4) formas posibles de superposición/intersección:
existing date periods: +--------------+ +-----+ +----+ +-----+ contains contained by touches testing periods: +------+ +------------+ +---------+ Para probar todas las formas posibles de superposición, puede utilizar el daterange de superposición de rango de fechas: &&
select count(*) from booking where daterange(from_date, to_date, '[]') && daterange('2017-04-20', '2017-04-25', '[]');Pero tenga cuidado : solo el uso de este tipo de verificación manual no evitará la inserción de rangos de fechas superpuestos en alta concurrencia. Hay una ventana (pequeña), después de esta prueba y antes de la inserción real de otra declaración simultánea para insertar una fila en conflicto. Para evitar eso también, puede usar restricciones de exclusión :
alter table booking add constraint exclude_overlapping_bookings exclude using gist (daterange(from_date, to_date, '[]') with &&); Nota : el operador de superposiciones de rango de fechas ( && ) funciona de la misma manera que el operador de overlaps , mencionado por daterange . Excepto:
[) , lo que significa: el límite inferior es inclusivo, pero el límite superior es exclusivo. Con overlaps , esta es la única inclusión admitida.overlaps funcionan con la timestamp with time zone . Sus valores de date se convertirán en eso, usando la medianoche como hora y la configuración de TimeZone actual. Esto puede o no ser lo que quieres.Solo para examinar otra forma, otra consulta que no usa el operador de superposición, sino solo AND et OR: (usando datos publicados por a_horse...). Esta es la lógica:
TO_DATE>= [tu fecha de inicio] AND TO_DATE<= [tu fecha de finalización]
O
FROM_DATE <= [tu fecha de finalización] AND FROM_DATE>= [tu fecha de inicio]
select * from bookings where to_date>=date '2017-04-18' AND to_date<=date '2017-04-19' OR from_date<= date '2017-04-19' AND from_date>=date '2017-04-18'; select * from bookings where to_date>=date '2017-04-20' AND to_date<=date '2017-04-25' OR from_date<= date '2017-04-25' AND from_date>=date '2017-04-20';Utilice el operador de overlaps :
select count(*) = 0 as allow_booking from "table" where (from_date, to_date) overlaps (date '2017-04-20', date '2017-04-25');Eso también se encargará de las reservas que no se encuentren completamente en el rango de prueba.
La consulta devolverá true si la reserva está permitida y false en caso contrario.
Ejemplos:
create table bookings ( id serial, from_date date, to_date date ); insert into bookings (from_date, to_date) values (date '2017-04-20', date '2017-04-20'), (date '2017-04-20', date '2017-04-24'), (date '2017-04-26', date '2017-04-29');Entonces lo siguiente
select * from bookings where (from_date, to_date) overlaps (date '2017-04-18', date '2017-04-19'); no devolverá nada, entonces, count(*) = 0 devuelve true
La siguiente consulta:
select * from bookings where (from_date, to_date) overlaps (date '2017-04-20', date '2017-04-25');devoluciones:
id | from_date | to_date ---+------------+----------- 1 | 2017-04-20 | 2017-04-20 2 | 2017-04-20 | 2017-04-24 Entonces count(*) = 0 devuelve false
Y la consulta:
select * from bookings where (from_date, to_date) overlaps (date '2017-04-27', date '2017-04-28');regresará:
id | from_date | to_date ---+------------+----------- 3 | 2017-04-26 | 2017-04-29 Y por eso count(*) = 0 también es falso.