Конфликты расписания MySQL - PullRequest
       12

Конфликты расписания MySQL

1 голос
/ 28 декабря 2008

Эй, я наткнулся на этот сайт в поисках решений для перекрытия событий в таблицах mySQL. Я был так впечатлен решением (которое уже помогает), я думал, что увижу, смогу ли я получить какую-то помощь ...

Хорошо, значит, Джо хочет поменяться сменой с кем-то на работе. У него свидание в суде. Он переходит к форме смены, и она подтягивает график этой недели (или то, что от него осталось). Это делается с помощью запроса к БД. Нет пота. Он выбирает смену. С этого момента становится колюче.

Итак, сначала форма передает начало и конец смены сценарию. Он запускает запрос для всех, кто имеет смену, которая перекрывает эту смену. Они не могут работать в две смены одновременно, поэтому все идентификаторы пользователей из этого запроса заносятся в черный список. Этот запрос выглядит так:

SELECT DISTINCT user_id FROM shifts
WHERE
FROM_UNIXTIME('$swap_shift_start') < shiftend
AND FROM_UNIXTIME('$swap_shift_end') > shiftstart

Затем мы выполняем запрос для всех смен, которые а) имеют одинаковую длину (политика компании) и б) не перекрываются с другими сменами, с которыми работает Джо.

То, что у меня сейчас есть, выглядит примерно так:

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

Теперь вы, вероятно, задаетесь вопросом "что такое $ threat_dates ???"

Что ж, когда Джо передает сменную смену, он перезагружает свои смены на неделю, если он решает проверить потенциал другой смены. Поэтому, когда он выполняет этот первый запрос, в то время как скрипт просматривает и выводит свой выбор, он также создает строку, которая выглядит примерно так:

AND NOT(
'joe_shift1_start' < shiftend
AND 'joe_shift1_end' > shiftstart)
AND NOT(
'joe_shift2_start' < shiftend
AND 'joe_shift2_end' > shiftstart)
...etc

Так что база данных получает довольно длинный запрос в следующем формате:

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

Итак, я надеюсь, что либо у SQL есть какой-то гениальный способ справиться с этим более простым способом, либо кто-то может указать на фантастический логический принцип, который объясняет потенциальные конфликты гораздо умнее. (Обратите внимание на использование 'start> end, end

Спасибо!

A

Ответы [ 2 ]

3 голосов
/ 28 декабря 2008

Я думаю, вы должны быть в состоянии исключить другие смены Джо, используя внутренний выбор вместо сгенерированной строки, что-то вроде:

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

По сути, каждая строка имеет внутренний запрос для подсчета сдвигов Джо, которые перекрываются, и гарантирует, что он равен нулю. Таким образом, будут возвращены только те строки, которые не перекрываются ни с одной из существующих смен Джо.

1 голос
/ 28 декабря 2008

Вы можете загрузить значения joe_shift{1,2,3} в таблицу TEMPORARY, а затем выполнить запрос для объединения с ней, используя внешнее объединение, чтобы найти только сдвиг, который не соответствует ни одному:

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

Из-за LEFT OUTER JOIN, когда в joes_shifts нет подходящей строки, столбцы имеют значение NULL.

...