Вопрос

Привет, я наткнулся на этот сайт в поисках решений для перекрытия событий в таблицах 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

Теперь вы, вероятно, задаетесь вопросом "что такое $conflict_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 есть какой-то гениальный способ справиться с этим более простым способом, либо кто-то может указать на фантастический логический принцип, который объясняет потенциальные конфликты гораздо более разумным способом.(Обратите внимание на использование 'начало > конец, end < начать", прежде чем я обнаружил, что использую промежуточные значения и мне пришлось вычесть по минуте с обоих концов.)

Спасибо!

A

Это было полезно?

Решение

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

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

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

Другие советы

Вы могли бы загрузить joe_shift{1,2,3} значения во ВРЕМЕННУЮ таблицу, а затем выполните запрос для объединения с ней, используя внешнее объединение, чтобы найти только те сдвиги, которые не соответствуют ни одному:

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

Из-за ЛЕВОГО ВНЕШНЕГО СОЕДИНЕНИЯ, когда нет совпадающей строки в joes_shifts, столбцы равны НУЛЮ.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top