嘿,我偶然发现了这个网站,正在寻找mySQL表中事件重叠的解决方案。我对这个解决方案印象深刻(已经很有帮助了),我想我应该看看我是否能得到更多的帮助……
好的,乔想和工作中的人换班。他有开庭日期。他打开换班表,调出本周的日程表(或者剩下的部分)。这是通过DB查询完成的。不客气。他选了一个班次。从这一点开始,事情就变得棘手了。
因此,首先,表单将shift start和shift end传递给脚本。它对班次与此班次重叠的任何人运行查询。他们不能同时工作两个班次,所以这个查询中的所有用户ID都被放在黑名单上。此查询如下所示:
SELECT DISTINCT user_id FROM shifts
WHERE
FROM_UNIXTIME('$swap_shift_start') < shiftend
AND FROM_UNIXTIME('$swap_shift_end') > shiftstart接下来,我们对a)相同长度(公司策略),b)不与Joe正在工作的任何其他班次重叠的所有班次运行查询。
我目前拥有的是这样的东西:
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?”
嗯,当Joe提交交换班次时,它会重新加载他当周的班次,以防他决定检查另一个班次的潜力。因此,当它执行第一个查询时,当脚本循环并输出他的选择时,它还构建了一个类似于以下内容的字符串:
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 < start‘的用法,在我发现我使用的是betweens之前,我不得不从两端减去一分钟。)
谢谢!
一个
发布于 2008-12-28 15:01:16
我认为您应该能够使用内部select而不是生成的字符串来排除Joe的其他移位,如下所示:
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的重叠班次计数,并确保它为零。因此,只有与Joe的任何现有移位不重叠的行才会被返回。
发布于 2008-12-28 08:45:33
您可以将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中没有匹配的行时,列为NULL。
https://stackoverflow.com/questions/395973
复制相似问题