Esta tabla se utiliza para almacenar sesiones (eventos):
CREATE TABLE session (
id int(11) NOT NULL AUTO_INCREMENT
, start_date date
, end_date date
);
INSERT INTO session
(start_date, end_date)
VALUES
("2010-01-01", "2010-01-10")
, ("2010-01-20", "2010-01-30")
, ("2010-02-01", "2010-02-15")
;
No queremos tener conflictos entre rangos.
Digamos que necesitamos insertar una nueva sesión de 2010-01-05 a 2010-01-25 .
Nos gustaría conocer las sesiones en conflicto.
Aquí está mi consulta:
SELECT *
FROM session
WHERE "2010-01-05" BETWEEN start_date AND end_date
OR "2010-01-25" BETWEEN start_date AND end_date
OR "2010-01-05" >= start_date AND "2010-01-25" <= end_date
;
Aquí está el resultado:
+----+------------+------------+
| id | start_date | end_date |
+----+------------+------------+
| 1 | 2010-01-01 | 2010-01-10 |
| 2 | 2010-01-20 | 2010-01-30 |
+----+------------+------------+
¿Existe una mejor manera de conseguirlo?
mysql
range
overlapping-matches
Pierre de LESPINAY
fuente
fuente
"2010-01-05" <= start_date AND "2010-01-25" >= end_date
. Consulte stackoverflow.com/a/28802972/632951 para ver la visualización. Su tercera condición actual nunca se evaluará, porque la primera (y la segunda) condición ya la cubre.Respuestas:
Tuve una consulta de este tipo con una aplicación de calendario que escribí una vez. Creo que usé algo como esto:
ACTUALIZACIÓN Esto definitivamente debería funcionar ((ns, ne, es, ee) = (new_start, new_end, existing_start, existing_end)):
Aquí hay un violín
fuente
=
en su código real en lugar de molestarse en quejarse.SELECT * FROM tbl WHERE existing_start BETWEEN $newStart AND $newEnd OR existing_end BETWEEN $newStart AND $newEnd OR $newStart BETWEEN existing_start AND existing_end if (!empty($result)) throw new Exception('We have overlapping')
Estas 3 líneas de cláusulas sql cubren los 4 casos de superposición requeridos.
fuente
La respuesta de Lamy es buena, pero puedes optimizarla un poco más.
SELECT * FROM tbl WHERE existing_start BETWEEN $newSTart AND $newEnd OR $newStart BETWEEN existing_start AND existing_end
Esto detectará los cuatro escenarios donde los rangos se superponen y excluirá los dos donde no lo hacen.
fuente
Me había enfrentado a un problema similar. Mi problema fue dejar de reservar entre un rango de fechas bloqueadas. Por ejemplo, la reserva está bloqueada para una propiedad entre el 2 de mayo y el 7 de mayo. Necesitaba encontrar cualquier tipo de fecha superpuesta para detectar y detener la reserva. Mi solución es similar a LordJavac.
SELECT * FROM ib_master_blocked_dates WHERE venue_id=$venue_id AND ( (mbd_from_date BETWEEN '$from_date' AND '$to_date') OR (mbd_to_date BETWEEN '$from_date' AND '$to_date') OR ('$from_date' BETWEEN mbd_from_date AND mbd_to_date) OR ('$to_date' BETWEEN mbd_from_date AND mbd_to_date) ) *mbd=master_blocked_dates
Avísame si no funciona.
fuente
Dados dos intervalos como (s1, e1) y (s2, e2) con s1 <e1 y s2 <e2
Puede calcular la superposición de la siguiente manera:
SELECT s1, e1, s2, e2, ABS(e1-s1) as len1, ABS(e2-s2) as len2, GREATEST(LEAST(e1, e2) - GREATEST(s1, s2), 0)>0 as overlaps, GREATEST(LEAST(e1, e2) - GREATEST(s1, s2), 0) as overlap_length FROM test_intervals
También funcionará si un intervalo está dentro del otro.
fuente
Recientemente, estaba luchando con el mismo problema y terminé con este sencillo paso (puede que este no sea un buen enfoque o que consuma memoria):
SELECT * FROM duty_register WHERE employee = '2' AND ( ( duty_start_date BETWEEN {$start_date} AND {$end_date} OR duty_end_date BETWEEN {$start_date} AND {$end_date} ) OR ( {$start_date} BETWEEN duty_start_date AND duty_end_date OR {$end_date} BETWEEN duty_start_date AND duty_end_date) );
Esto me ayudó a encontrar las entradas con rangos de fechas superpuestos.
Espero que esto ayude a alguien.
fuente
Puede cubrir todos los casos de superposición de fechas incluso cuando hasta la fecha en la base de datos posiblemente pueda ser nulo de la siguiente manera:
SELECT * FROM `tableName` t WHERE t.`startDate` <= $toDate AND (t.`endDate` IS NULL OR t.`endDate` >= $startDate);
Esto devolverá todos los registros que se superponen con las nuevas fechas de inicio / finalización de todos modos.
fuente
La respuesta de Mackraken anterior es mejor desde una perspectiva de desempeño, ya que no requiere varios OR para evaluar si dos fechas se superponen. ¡Buena solución!
Sin embargo, encontré que en MySQL necesitas usar DATEDIFF en lugar del operador menos -
SELECT o.orderStart, o.orderEnd, s.startDate, s.endDate , GREATEST(LEAST(orderEnd, endDate) - GREATEST(orderStart, startDate), 0)>0 as overlaps , DATEDIFF(LEAST(orderEnd, endDate), GREATEST(orderStart, startDate)) as overlap_length FROM orders o JOIN dates s USING (customerId) WHERE 1 AND DATEDIFF(LEAST(orderEnd, endDate),GREATEST(orderStart, startDate)) > 0;
fuente