In dieser Tabelle werden Sitzungen (Ereignisse) gespeichert:
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")
;
Wir wollen keinen Konflikt zwischen Bereichen haben.
Angenommen, wir müssen eine neue Sitzung vom 05.01.2010 bis zum 25.01.2010 einfügen .
Wir möchten die widersprüchlichen Sitzungen kennen.
Hier ist meine Frage:
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
;
Hier ist das Ergebnis:
+----+------------+------------+
| id | start_date | end_date |
+----+------------+------------+
| 1 | 2010-01-01 | 2010-01-10 |
| 2 | 2010-01-20 | 2010-01-30 |
+----+------------+------------+
Gibt es einen besseren Weg, um das zu bekommen?
mysql
range
overlapping-matches
Pierre de LESPINAY
quelle
quelle
"2010-01-05" <= start_date AND "2010-01-25" >= end_date
. Visualisierung finden Sie unter stackoverflow.com/a/28802972/632951 . Ihre aktuelle dritte Bedingung wird niemals ausgewertet, da die erste (und zweite) Bedingung sie bereits abdeckt.Antworten:
Ich hatte eine solche Anfrage mit einer Kalenderanwendung, die ich einmal geschrieben habe. Ich glaube, ich habe so etwas benutzt:
UPDATE Dies sollte auf jeden Fall funktionieren ((ns, ne, es, ee) = (neuer_Start, neues_Ende, vorhandener_Start, vorhandenes_Ende)):
Hier ist eine Geige
quelle
=
in seinen eigentlichen Code eingefügt, anstatt sich darüber zu beschweren.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')
Diese 3 Zeilen mit SQL-Klauseln decken die 4 erforderlichen Überlappungsfälle ab.
quelle
Lamys Antwort ist gut, aber Sie können sie ein wenig weiter optimieren.
SELECT * FROM tbl WHERE existing_start BETWEEN $newSTart AND $newEnd OR $newStart BETWEEN existing_start AND existing_end
Dadurch werden alle vier Szenarien erfasst, in denen sich die Bereiche überschneiden, und die beiden ausgeschlossen, in denen dies nicht der Fall ist.
quelle
Ich hatte mich dem ähnlichen Problem gestellt. Mein Problem war, die Buchung zwischen einer Reihe blockierter Daten zu beenden. Beispielsweise ist die Buchung für eine Unterkunft zwischen dem 2. und 7. Mai gesperrt. Ich musste ein überlappendes Datum finden, um die Buchung zu erkennen und zu stoppen. Meine Lösung ähnelt 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
Lassen Sie mich wissen, wenn es nicht funktioniert.
quelle
Bei zwei Intervallen wie (s1, e1) und (s2, e2) mit s1 <e1 und s2 <e2 können
Sie Überlappungen wie folgt berechnen:
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
Funktioniert auch, wenn ein Intervall innerhalb des anderen liegt.
quelle
Vor kurzem hatte ich mit dem gleichen Problem zu kämpfen und endete mit diesem einfachen Schritt (dies ist möglicherweise kein guter Ansatz oder speicherintensiv) -
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) );
Dies hat mir geholfen, Einträge mit überlappenden Datumsbereichen zu finden.
Hoffe das hilft jemandem.
quelle
Sie können alle datumsüberlappenden Fälle abdecken, auch wenn das aktuelle Datum in der Datenbank möglicherweise wie folgt null sein kann:
SELECT * FROM `tableName` t WHERE t.`startDate` <= $toDate AND (t.`endDate` IS NULL OR t.`endDate` >= $startDate);
Dadurch werden ohnehin alle Datensätze zurückgegeben, die sich mit den neuen Start- / Enddaten überschneiden.
quelle
Die obige Antwort von Mackraken ist aus Sicht der Leistung besser, da nicht mehrere OPs erforderlich sind, um zu bewerten, ob sich zwei Daten überschneiden. Schöne Lösung!
Ich habe jedoch festgestellt, dass Sie in MySQL DATEDIFF anstelle des Minusoperators verwenden müssen -
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;
quelle