MySQL的日程安排冲突
题
嘿,我偶然发现这个网站寻找解决方案的事件在MySQL表重叠。我是该解决方案印象深刻(这已经帮助),我想我会看到,如果我能得到一些更多的帮助...
好吧,乔想对某人在工作中交换的变化。他有一个开庭日期。他去转变交换表,并拉起这一周的日程安排(或者还剩下些什么呢)。这与DB查询完成。无汗。他拿起一个转变。从这一点来说,它得到刺。
因此,首先,通过形式移位开始和换档结束给脚本。它运行的人谁都有重叠,这种转变的转变查询。他们不能马上开始工作两个班次,所以从这个查询所有用户ID被放在黑名单上。这个查询看起来像:
SELECT DISTINCT user_id FROM shifts
WHERE
FROM_UNIXTIME('$swap_shift_start') < shiftend
AND FROM_UNIXTIME('$swap_shift_end') > shiftstart
接下来,我们运行是a)所述相同的长度(公司政策)所有班次的查询时,和b)不与任何其它移乔工作重叠。
我现在有是这样的:
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与这一个简单的方法处理的一些天才的方式,或者有人能指出的是占一个更聪明的方式潜在冲突一个梦幻般的逻辑主体。 (注意使用的“开始>端,端<开始”,前我发现我用中间人,不得不减去一分钟关闭两端。)
谢谢!
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');
由于左外的JOIN,当在没有joes_shifts
匹配的行,列都为NULL。