2010-03-30 17 views
56

Ce tableau est utilisé pour des séances de magasin (événements):Vérifier chevauchement des plages de dates dans MySQL

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. Supposons que nous devions insérer une nouvelle session de 2010-01-05 à 2010-01-25.

Nous aimerions connaître la (les) session (s) conflictuelle (s).

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 at-il une meilleure façon d'obtenir cela?


fiddle

+1

Votre troisième condition est erronée. Il est censé être '' 2010-01-05 "<= start_date AND" 2010-01-25 "> = end_date'. Voir http://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à. – Pacerier

Répondre

110

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

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

MISE À JOUR Cela devrait certainement travailler ((ns, ne, es, ee) = (new_start, new_end, existing_start, existing_end)):

  1. ns - ne - es - ee: ne se chevauchent pas et ne correspond pas (parce que ne < es)
  2. ns - es - ne - ee: les chevauchements et les matches
  3. es - ns - ee - ne: les chevauchements et matchs
  4. es - ee - ns - ne: ne se chevauchent pas et ne correspond pas (parce que ns> ee)
  5. es - ns - ne - ee: les chevauchements et les matches
  6. ns - es - ee - ne: chevauchements et correspond

Voici une fiddle

+0

@Glide: Je pense que cela devrait fonctionner, mis à jour la réponse – soulmerge

+6

Fonctionne bien !, mais je pense que @Pierre de LESPINAY recherche des gammes inclusives dans sa requête: WHERE new_start <= existing_end ET new_end> = existing_start; –

+11

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

18
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 nécessaire.

+3

bon travail mec :) – Adrian

+3

Même si l'OP ne recherchait apparemment pas cette définition de chevauchement, cette réponse est la meilleure solution pour le problème décrit par le nom de la question. Je cherchais ce chevauchement, qui est le vrai chevauchement. – Cec

+2

Fantastique, m'a sauvé un mal de tête massif. –

11

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 

Ceci attrapera les quatre scénarios où les plages se chevauchent et exclura les deux où elles ne le sont pas.

+0

Existe-t-il d'autres solutions que celles-ci et les deux précédentes? – Pacerier

3

J'avais rencontré 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 mai et le 7 mai. J'avais besoin de trouver toute sorte de date de chevauchement pour détecter et arrêter la réservation. Ma solution est similaire à LordJavac. Faites-moi savoir si cela ne fonctionne pas. Veuillez me faire savoir si cela ne fonctionne pas.

1

Compte tenu de deux intervalles comme (s1, e1) et (s2, e2) avec s1 < e1 et s2 < e2
Vous pouvez calculer chevauchez 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 

travaillera également si un intervalle est dans l'autre.

0

Récemment je luttais avec le même problème et est venu de mettre fin à cette seule étape (Cela peut ne pas être une bonne approche ou de la mémoire consommation) -

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 date de chevauchement gammes.

Espérons que cela aide quelqu'un.