web-dev-qa-db-fra.com

Vérifier le chevauchement des plages de dates dans MySQL

Ce tableau est utilisé pour stocker des sessions (événements):

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")
;

Nous ne voulons pas avoir de conflit entre les gammes.
Disons que nous devons insérer une nouvelle session de 2010-01-05 à 2010-01-25.
Nous aimerions connaître la (les) session (s) en conflit.

Voici ma requête:

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
;

Voici le résultat:

+----+------------+------------+
| id | start_date | end_date   |
+----+------------+------------+
|  1 | 2010-01-01 | 2010-01-10 |
|  2 | 2010-01-20 | 2010-01-30 |
+----+------------+------------+

Y a-t-il une meilleure façon de l'obtenir?


violon

67
Pierre de LESPINAY

J'ai eu une telle requête avec une application de calendrier que j'ai écrit une fois. Je pense avoir utilisé quelque chose comme ceci:

... WHERE new_start < existing_end
      AND new_end   > existing_start;

UPDATE Ceci devrait fonctionner ((ns, ne, es, ee) = (new_start, new_end, existing_start, existing_end)):

  1. ns - ne - es - ee: ne se chevauchent pas et ne correspondent pas (car ne <es)
  2. ns - es - ne - ee: chevauchements et correspondances
  3. es - ns - ee - ne: chevauchements et correspondances
  4. es - ee - ns - ne: ne se chevauchent pas et ne correspondent pas (car ns> ee)
  5. es - ns - ne - ee: chevauchements et correspondances
  6. ns - es - ee - ne: chevauchements et correspondances

Voici un violon

128
soulmerge
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')

Ces 3 lignes de clauses sql couvrent les 4 cas de chevauchement requis.

23
Lamy

La réponse de Lamy est bonne, mais vous pouvez l'optimiser un peu plus.

SELECT * FROM tbl WHERE
existing_start BETWEEN $newSTart AND $newEnd OR
$newStart BETWEEN existing_start AND existing_end

Cela intercepte les quatre scénarios où les plages se chevauchent et exclut les deux où ils ne le font pas.

13
LordJavac

J'avais affronté le même problème. Mon problème était d'arrêter de réserver entre une série de dates bloquées. Par exemple, la réservation est bloquée pour une propriété entre le 2 et le 7 mai. Je devais trouver tout type de date de chevauchement pour détecter et arrêter la réservation. Ma solution est similaire à 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

Faites-moi savoir si cela ne fonctionne pas.

4
Niraj Kumar

Étant donné deux intervalles comme (s1, e1) et (s2, e2) avec s1 <e1 et s2 <e2
Vous pouvez calculer le chevauchement comme ceci:

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 

Cela fonctionnera également si un intervalle est dans l’autre.

1
Mackraken

Récemment, je me débattais avec le même problème et m’arrivais à la fin avec cette étape facile (cela peut ne pas être une bonne approche ou consommer de la mémoire)

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)
);

Cela m'a aidé à trouver les entrées avec des plages de dates qui se chevauchent.

J'espère que ça aide quelqu'un.

0
Vishal Kumar Sahu