MySQL计划冲突

时间:2008-12-28 08:22:32

标签: mysql datetime calendar schedule

嘿,我偶然发现这个网站正在寻找mySQL表中事件重叠的解决方案。我对解决方案印象深刻(已经有所帮助)我想我会看到能不能得到更多的帮助......

好的,所以Joe希望与工作中的某个人交换班次。他有一个法庭约会。他进入班次交换表格,它拉起了本周的时间表(或剩下的时间表)。这是通过数据库查询完成的。没有汗水。他选择了一个班次。从这一点来说,它变得棘手。

因此,首先,表单将shift开始和shift结束传递给脚本。它为任何具有与此班次重叠的班次的人运行查询。它们不能同时处理两个班次,因此此查询中的所有用户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 ???”

好吧,当乔提交换班时,如果他决定检查另一个班次的潜力,它会重新加载他一周的班次。因此,当它执行第一个查询时,当脚本循环并输出他的选择时,它也会构建一个看起来像这样的字符串:

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&gt; end,end&lt; start',然后才发现我正在使用它们之间并且必须从两端减去一分钟。)

谢谢!

A

2 个答案:

答案 0 :(得分:3)

我认为你应该能够使用内部选择而不是生成的字符串来排除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的任何现有班次不重叠的行。

答案 1 :(得分:1)

您可以将joe_shift{1,2,3}值加载到TEMPORARY表中,然后执行查询以加入它,使用外部联接仅查找与任何不匹配的shift:

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。