MySQL Zeitplan Konflikte
Frage
Hey, stieß ich auf dieser Seite der Suche nach Lösungen für die Veranstaltung in mySQL-Tabellen überlappt. Ich war so beeindruckt von der Lösung (die hilft schon) Ich dachte, ich würde sehen, ob ich etwas mehr Hilfe bekommen könnte ...
Okay, so Joe will die Verschiebungen bei der Arbeit mit jemandem tauschen. Er hat einen Gerichtstermin. Er geht auf die Verschiebung Swap Form und es in dieser Woche Zeitplan nach oben ziehen (oder was davon übrig ist). Dies wird mit einer DB-Abfrage durchgeführt. Kein Schweiß. Er nimmt eine Verschiebung. Ab diesem Zeitpunkt wird es stachelig.
Also, zuerst, so geht die Form der Schichtbeginn und -ende an das Skript. Es führt eine Abfrage für alle, die eine Verschiebung hat, die diese Verschiebung überlappt. Sie können nicht zwei Schichten arbeiten auf einmal, so dass alle Benutzer-IDs aus dieser Abfrage werden auf eine schwarze Liste setzen. Diese Abfrage wie folgt aussieht:
SELECT DISTINCT user_id FROM shifts
WHERE
FROM_UNIXTIME('$swap_shift_start') < shiftend
AND FROM_UNIXTIME('$swap_shift_end') > shiftstart
Als nächstes führen wir eine Abfrage für alle Schichten, die a) die gleiche Länge (Unternehmenspolitik) sind, und b) überlappen sich nicht mit anderen Verschiebungen Joe arbeitet.
Was ich zur Zeit haben, ist so etwas wie folgt aus:
SELECT *
FROM shifts
AND shiftstart BETWEEN FROM_UNIXTIME('$startday') AND FROM_UNIXTIME('$endday')
AND user_id NOT IN ($busy_users)
AND (TIME_TO_SEC(TIMEDIFF(shiftend,shiftstart)) = '$swap_shift_length')
$conflict_dates
ORDER BY shiftstart, lastname
Jetzt sind Sie wahrscheinlich fragen, "was $ conflict_dates ist ???"
Nun, wenn Joe die Swap-Verschiebung vorträgt, lädt es seine Verschiebungen für die Woche, falls er eine weitere Verschiebung Potenzial zu überprüfen, entscheidet. Also, wenn es tut, dass erste Abfrage, während das Skript durch geloopt und seine Entscheidungen ausgibt, wird es auch einen String bauen, die Art wie folgt aussieht:
AND NOT(
'joe_shift1_start' < shiftend
AND 'joe_shift1_end' > shiftstart)
AND NOT(
'joe_shift2_start' < shiftend
AND 'joe_shift2_end' > shiftstart)
...etc
Damit die Datenbank der eine ziemlich lange Abfrage entlang der Linien von:
SELECT *
FROM shifts
AND shiftstart BETWEEN FROM_UNIXTIME('$startday') AND FROM_UNIXTIME('$endday')
AND user_id NOT IN ('blacklisteduser1', 'blacklisteduser2',...etc)
AND (TIME_TO_SEC(TIMEDIFF(shiftend,shiftstart)) = '$swap_shift_length')
AND NOT(
'joe_shift1_start' < shiftend
AND 'joe_shift1_end' > shiftstart)
AND NOT(
'joe_shift2_start' < shiftend
AND 'joe_shift2_end' > shiftstart)
AND NOT(
'joe_shift3_start' < shiftend
AND 'joe_shift3_end' > shiftstart)
AND NOT(
'joe_shift4_start' < shiftend
AND 'joe_shift4_end' > shiftstart)
...etc
ORDER BY shiftstart, lastname
Also, meine Hoffnung ist, dass entweder SQL einige Genie Art und Weise hat mit diesem in einer einfacheren Art und Weise des Umgangs, oder dass jemand kann ein fantastisches logisches Haupt weist darauf hin, dass für die möglichen Konflikte in eine viel intelligentere Weise ausmacht. (Beachten Sie die Verwendung des ‚Start> Ende, Ende Danke! A
Lösung
Ich glaube, Sie sollten Joes andere Verschiebungen der Lage sein, ausschließen eine innere wählen Sie anstelle der erzeugten Zeichenfolge verwendet wird, so etwas wie:
SELECT *
FROM shifts s1
AND shiftstart BETWEEN FROM_UNIXTIME('$startday') AND FROM_UNIXTIME('$endday')
AND user_id NOT IN ($busy_users)
AND (TIME_TO_SEC(TIMEDIFF(shiftend,shiftstart)) = '$swap_shift_length')
AND (SELECT COUNT(1) FROM shifts s2
WHERE s2.user_id = $joes_user_id
AND s1.shiftstart < s2.shiftend
AND s2.shiftstart < s1.shiftend) = 0
ORDER BY shiftstart, lastname
Grundsätzlich hat jede Zeile eine innere Abfrage für die Zählung von Joes Verschiebungen, die sich überlappen, und stellt sicher, dass es Null. Somit werden nur die Zeilen, die mit einem der Joe bestehenden Verschiebungen zurückgegeben werden nicht überlappen.
Andere Tipps
Sie könnten die joe_shift{1,2,3}
Werte in eine temporäre Tabelle laden und dann eine Abfrage gegen sie zu verbinden, eine Außen mit join nur Verschiebung zu finden, die nicht passen:
CREATE TEMPORARY TABLE joes_shifts (
shiftstart DATETIME
shiftend DATETIME
);
INSERT INTO joes_shifts (shiftstart, shiftend) VALUES
('$joe_shift1_start', '$joe_shift1_end'),
('$joe_shift2_start', '$joe_shift2_end'),
('$joe_shift3_start', '$joe_shift3_end'),
('$joe_shift4_start', '$joe_shift4_end');
-- make sure you have validated these variables to prevent SQL injection
SELECT s.*
FROM shifts s
LEFT OUTER JOIN joes_shifts j
ON (j.shiftstart < s.shiftend OR j.shiftend > s.shiftstart)
WHERE j.shiftstart IS NULL
AND s.shiftstart BETWEEN FROM_UNIXTIME('$startday') AND FROM_UNIXTIME('$endday')
AND s.user_id NOT IN ('blacklisteduser1', 'blacklisteduser2',...etc)
AND (TIME_TO_SEC(TIMEDIFF(s.shiftend,s.shiftstart)) = '$swap_shift_length');
Aufgrund der LEFT OUTER JOIN, wenn es keine passende Zeile in joes_shifts
ist, die Spalten sind NULL.