84 votes

Vérifier le chevauchement des plages de dates dans MySQL

Cette table est utilisée pour stocker les 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 qu'il y ait de conflit entre les gammes.
Disons que nous devons insérer une nouvelle session à partir de 2010-01-05 a 2010-01-25 .
Nous aimerions connaître la ou les sessions en conflit.

Voici ma question :

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 un meilleur moyen de l'obtenir ?


violon

1 votes

Votre troisième condition est fausse. Elle est censée être "2010-01-05" <= start_date AND "2010-01-25" >= end_date . Voir stackoverflow.com/a/28802972/632951 pour la visualisation. Votre troisième condition actuelle ne sera jamais évaluée, car la première (et la deuxième) condition la couvre déjà.

163voto

soulmerge Points 37314

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

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

UPDATE Cela devrait définitivement fonctionner ((ns, ne, es, ee) = (new_start, new_end, existing_start, existing_end)) :

  1. ns - ne - es - ee : ne se chevauche pas et ne correspond pas (parce que 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 chevauche pas et ne correspond pas (parce que ns > ee)
  5. es - ns - ne - ee : chevauchements et correspondances
  6. ns - es - ee - ne : chevauchements et correspondances

Voici un violon

7 votes

Cela fonctionne très bien, mais je pense que @Pierre de LESPINAY cherche des plages inclusives dans sa requête : WHERE new_start <= existing_end AND new_end >= existing_start ;

18 votes

@OsvaldoM. S'il l'était vraiment, il se serait plaint il y a environ 2 ans

0 votes

Si un événement se termine aujourd'hui et qu'un autre commence aujourd'hui, se chevauchent-ils ? A mon avis, ils se chevaucheront. Mais la requête SQL ne le dira pas : sqlfiddle.com/#!2/0a6fd/1/0

34voto

Lamy Points 1127
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.

7 votes

Même si le PO ne cherchait apparemment pas cette définition de chevauchement, cette réponse est la meilleure solution au problème décrit par le nom de la question. Je cherchais ce chevauchement, qui est le véritable chevauchement.

2 votes

Je ne suis pas sûr de ce que vous entendez par "véritable chevauchement" mais la réponse du haut par @soulmerge est équivalente à cette réponse par Lamy. J'ai pu utiliser le résolveur de théorèmes Z3 pour prouver l'équivalence : grantjenks.com/projets/equivalent-inequalities

18voto

LordJavac Points 171

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 permettra de prendre en compte les quatre scénarios où les plages se chevauchent et d'exclure les deux scénarios où elles ne se chevauchent pas.

0 votes

Y a-t-il d'autres solutions que celle-ci et les deux autres ci-dessus ?

4voto

Niraj Kumar Points 1

J'ai été confronté au même problème. Mon problème était d'arrêter les réservations entre une série de dates bloquées. Par exemple, la réservation est bloquée pour une propriété entre le 2 mai et le 7 mai. J'avais besoin de trouver n'importe quel type de date de chevauchement pour détecter et arrêter la réservation. Ma solution est similaire à celle de 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 ça ne marche pas.

3voto

Mackraken Points 337

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

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 se trouve à l'intérieur d'un autre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X