所以这是我在这里的第一个问题之一,但我有一点点变化:
所以我有两个人的日程安排在数据库中。时间表只记录两个用户的各种事件/约会的开始时间,结束时间和描述。
PersonA希望与PersonB交易约会。我想要一个MySQL查询,它将返回PersonB和PersonA可以交换的所有时间。
最初查询的参数是抛弃与PersonA重叠的任何PersonB约会,而PersonB的约会必须与PersonA想要交换的约会完全相同。我得到了一些关于时间算术/几何的好建议,帮助我得到了我需要的结果。
现在我想更改1对1参数,以使约会的长度不必相等。因此,如果PersonA想要交换他周一早上的预约(上午10:00 - 上午11:30),查询将:
因此,如果PersonA想要交换上述约会(再次,周一上午10:00 - 上午11:30),并且PersonA在周二下午1:00到3:00预约,而PersonB在周二预约从中午12:00到下午4:00,查询将返回:
Possible_Swaps
==============
userID | Start | End | Description
PersonB | Tuesday, 12:00 PM | Tuesday 1:00 PM | Cooking
PersonB | Tuesday, 4:00 PM | Tuesday 5:00 PM | Cooking
除了任何其他可能性。这对数据库来说太过期待了吗?如果是这样,关于如何至少获得重叠但有时间悬于两边以便PHP脚本可以处理它们的任何建议?
根据searlea的要求,这里有更多的背景:
我一直在说约会,但我认为我的意思是“工作”,就像“工作班次”一样。 PersonA和PersonB在同一个办公室工作。在vcalendar中,工作班次通常被称为“事件”,但偶尔会被称为“约会”,而我选择后者,因为它听起来不像是两个人参加公平。
所以PersonA在星期一上午10点到11点30分洗碗。 PersonB将于周二中午12:00至下午5:00做饭。 PersonA在周一离开城镇之前真的想见到他的兄弟。他宁愿周一早上全部休息,但他还是愿意接受一个小时的转移。
所以在我的旧模型中(在my very first question这里提出来),我正在寻找没有重叠的任何班次以及班次在时间上相等的地方。但这有两个问题:
如果我需要有人在星期二工作2小时,我星期四工作4小时,乔周四工作8小时,我可以换掉他的两个小时,他可以早点离开我可以待一会儿。
如果我有两个小时的班次,但我很乐意交换一小时的时间,只是为了准时到达机场,我想知道这样的事情是否比我之前提前一小时到来在这一周,所以我可以把他的那一部分转移。
长话短说(太晚了),我想要显然被称为PersonA转移到PersonB的relative complement(基本上任何时候PersonB正在工作而PersonA不是,不管转移是否重叠在一些其他一点。)
理想情况下,我会得到一组结果,其中包括PersonB正在工作的位和PersonA不是(上面提到的两个1小时的班次),以及整个班次(带有特殊标签表示它不是总体而言可以看到PersonA会看到他正在覆盖一个班次的一部分并且不会感到困惑,并且认为PersonB正好碰巧工作了两个小时。
这一切都开始听起来有点复杂。基本上我希望PersonB的转变为蓝色,PersonA转变为黄色,我希望数据库返回所有不是绿色的部分。
答案 0 :(得分:1)
SELECT *
FROM schedule AS s1
WHERE
s1.user = 'Ondra'
AND
NOT EXISTS (
SELECT * FROM schedule AS s2
WHERE
s2.user = 'Zizka'
AND (
s2.start BETWEEN s1.start AND s1.end
OR
s2.end BETWEEN s1.start AND s1.end
OR
s1.start > s2.start AND s1.end < s2.end
)
)
这选择了Ondra的事件,这些事件可以适应Zizka日记中的空白。
编辑:原来它是一个交叉点,但如果你想要相对补充,这就足够了。
答案 1 :(得分:0)
让$shift_id
成为您的用户想要转换的转变的ID。
select swappable.shift_id, swappable.user_id, swappable.description,
FROM_UNIXTIME(swappable.shiftstart) as start,
FROM_UNIXTIME(swappable.shiftend) as end,
(swappable.shiftend - swappable.shiftstart) -
sum(coalesce(least(conflict.shiftend, swappable.shiftend) -
greatest(conflict.shiftstart, swappable.shiftstart), 0))
as swaptime,
group_concat(conflict.shift_id) as conflicts,
group_concat(concat(FROM_UNIXTIME(conflict.shiftstart), ' - ',
FROM_UNIXTIME(conflict.shiftend))) as conflict_times
from shifts as problem
join shifts as swappable on swappable.user_id != problem.user_id
left join shifts as conflict on conflict.user_id = problem.user_id
and conflict.shiftstart < swappable.shiftend
and conflict.shiftend > swappable.shiftstart
where problem.shift_id = 1
group by swappable.shift_id
having swaptime > 0;
经过测试:
CREATE TABLE `shifts` (
`shift_id` int(10) unsigned NOT NULL auto_increment,
`user_id` varchar(20) NOT NULL,
`shiftstart` int unsigned NOT NULL,
`shiftend` int unsigned NOT NULL,
`description` varchar(32) default NULL,
PRIMARY KEY (`shift_id`)
);
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (1,'april', UNIX_TIMESTAMP('2009-04-04 10:00:00'),UNIX_TIMESTAMP('2009-04-04 12:00:00'),'Needs to be swapped');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (2,'bill', UNIX_TIMESTAMP('2009-04-04 10:30:00'),UNIX_TIMESTAMP('2009-04-04 11:30:00'),'Inside today');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (3,'casey', UNIX_TIMESTAMP('2009-04-04 12:00:00'),UNIX_TIMESTAMP('2009-04-04 14:00:00'),'Immediately after today');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (4,'casey', UNIX_TIMESTAMP('2009-04-04 08:00:00'),UNIX_TIMESTAMP('2009-04-04 10:00:00'),'Immediately before today');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (5,'david', UNIX_TIMESTAMP('2009-04-04 11:00:00'),UNIX_TIMESTAMP('2009-04-04 15:00:00'),'Partly after today');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (6,'april', UNIX_TIMESTAMP('2009-04-05 10:00:00'),UNIX_TIMESTAMP('2009-04-05 12:00:00'),'Tommorow');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (7,'bill', UNIX_TIMESTAMP('2009-04-05 09:00:00'),UNIX_TIMESTAMP('2009-04-05 11:00:00'),'Partly before tomorrow');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (8,'casey', UNIX_TIMESTAMP('2009-04-05 10:00:00'),UNIX_TIMESTAMP('2009-04-05 12:00:00'),'Equals tomorrow');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (9,'david', UNIX_TIMESTAMP('2009-04-05 10:30:00'),UNIX_TIMESTAMP('2009-04-05 11:30:00'),'Inside tomorrow');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (10,'april',UNIX_TIMESTAMP('2009-04-11 10:00:00'),UNIX_TIMESTAMP('2009-04-11 12:00:00'),'Next week');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (11,'april',UNIX_TIMESTAMP('2009-04-11 12:00:00'),UNIX_TIMESTAMP('2009-04-11 14:00:00'),'Second shift');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (12,'bill', UNIX_TIMESTAMP('2009-04-11 11:00:00'),UNIX_TIMESTAMP('2009-04-11 13:00:00'),'Overlaps two');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (13,'casey',UNIX_TIMESTAMP('2009-04-11 17:00:00'),UNIX_TIMESTAMP('2009-04-11 19:00:00'),'No conflict');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (14,'april',UNIX_TIMESTAMP('2009-05-04 10:00:00'),UNIX_TIMESTAMP('2009-05-04 12:00:00'),'Next month');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (15,'april',UNIX_TIMESTAMP('2009-05-04 13:00:00'),UNIX_TIMESTAMP('2009-05-04 15:00:00'),'After break');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (16,'bill', UNIX_TIMESTAMP('2009-05-04 11:00:00'),UNIX_TIMESTAMP('2009-05-04 14:00:00'),'Middle okay');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (17,'april',UNIX_TIMESTAMP('2010-04-04 10:00:00'),UNIX_TIMESTAMP('2010-04-04 11:00:00'),'Next year');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (18,'april',UNIX_TIMESTAMP('2010-04-04 11:30:00'),UNIX_TIMESTAMP('2010-04-04 12:00:00'),'After break');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (19,'april',UNIX_TIMESTAMP('2010-04-04 12:30:00'),UNIX_TIMESTAMP('2010-04-04 13:30:00'),'Third part');
insert into `shifts`(`shift_id`,`user_id`,`shiftstart`,`shiftend`,`description`) values (20,'bill', UNIX_TIMESTAMP('2010-04-04 10:30:00'),UNIX_TIMESTAMP('2010-04-04 13:00:00'),'Two parts okay');
结果:
'shift_id', 'user_id', 'description', 'start', 'end', 'swaptime', 'conflicts', 'conflict_times'
'3', 'casey', 'Immediately after today', '2009-04-04 12:00:00', '2009-04-04 14:00:00', '7200', NULL, NULL
'4', 'casey', 'Immediately before today', '2009-04-04 08:00:00', '2009-04-04 10:00:00', '7200', NULL, NULL
'5', 'david', 'Partly after today', '2009-04-04 11:00:00', '2009-04-04 15:00:00', '10800', '1', '2009-04-04 10:00:00 - 2009-04-04 12:00:00'
'7', 'bill', 'Partly before tomorrow', '2009-04-05 09:00:00', '2009-04-05 11:00:00', '3600', '6', '2009-04-05 10:00:00 - 2009-04-05 12:00:00'
'13', 'casey', 'No conflict', '2009-04-11 17:00:00', '2009-04-11 19:00:00', '7200', NULL, NULL
'16', 'bill', 'Middle okay', '2009-05-04 11:00:00', '2009-05-04 14:00:00', '3600', '15,14', '2009-05-04 13:00:00 - 2009-05-04 15:00:00,2009-05-04 10:00:00 - 2009-05-04 12:00:00'
'20', 'bill', 'Two parts okay', '2010-04-04 10:30:00', '2010-04-04 13:00:00', '3600', '19,18,17', '2010-04-04 12:30:00 - 2010-04-04 13:30:00,2010-04-04 11:30:00 - 2010-04-04 12:00:00,2010-04-04 10:00:00 - 2010-04-04 11:00:00'
这显示了可以交换任何部分的所有班次,包括如何
很多总时间(以秒为单位)是可交换的。最后一栏conflict_times
,
显示交换用户已安排工作的时间。
应用程序应该很容易从中提取可用时间;
这在MySQL中是可能的,但非常棘手。
答案 2 :(得分:0)
返回两个不同用户的所有间隔,但重叠的部分除外。
CREATE TABLE IF NOT EXISTS `shifts` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(1) NOT NULL,
`start` datetime NOT NULL,
`end` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=12 ;
INSERT INTO `shifts` (`id`, `name`, `start`, `end`) VALUES
(1, 'a', '2000-01-01 01:00:00', '2000-01-01 03:00:00'),
(2, 'a', '2000-01-01 06:00:00', '2000-01-01 07:30:00'),
(3, 'b', '2000-01-01 02:00:00', '2000-01-01 04:00:00'),
(4, 'b', '2000-01-01 05:00:00', '2000-01-01 07:00:00'),
(5, 'a', '2000-01-01 08:00:00', '2000-01-01 11:00:00'),
(6, 'b', '2000-01-01 09:00:00', '2000-01-01 10:00:00'),
(7, 'a', '2000-01-01 12:00:00', '2000-01-01 13:00:00'),
(8, 'b', '2000-01-01 14:00:00', '2000-01-01 14:30:00'),
(9, 'a', '2000-01-01 16:00:00', '2000-01-01 18:00:00'),
(10, 'a', '2000-01-01 19:00:00', '2000-01-01 21:00:00'),
(11, 'b', '2000-01-01 17:00:00', '2000-01-01 20:00:00');
id name start end
1 a 2000-01-01 01:00:00 2000-01-01 02:00:00
3 b 2000-01-01 03:00:00 2000-01-01 04:00:00
4 b 2000-01-01 05:00:00 2000-01-01 06:00:00
2 a 2000-01-01 07:00:00 2000-01-01 07:30:00
5 a 2000-01-01 10:00:00 2000-01-01 11:00:00
7 a 2000-01-01 12:00:00 2000-01-01 13:00:00
8 b 2000-01-01 14:00:00 2000-01-01 14:30:00
9 a 2000-01-01 16:00:00 2000-01-01 17:00:00
11 b 2000-01-01 18:00:00 2000-01-01 19:00:00
10 a 2000-01-01 20:00:00 2000-01-01 21:00:00
我使用MySQL的一个名为User-Defined Variables的功能来实现以下查询的目标:
SET @inA=0, @inB=0, @lastAstart = 0, @lastBstart = 0, @lastAend = 0, @lastBend = 0;
SELECT id,name,start,end FROM (
SELECT
id,name,
IF(name='a',
IF(UNIX_TIMESTAMP(start) > @lastBend, start, FROM_UNIXTIME(@lastBend)),
IF(UNIX_TIMESTAMP(start) > @lastAend, start, FROM_UNIXTIME(@lastAend))
) as start,
IF(name='a',
IF(@inB,FROM_UNIXTIME(@lastBstart),end),
IF(@inA,FROM_UNIXTIME(@lastAstart),end)
) as end,
IF(name='a',
IF(@inB AND (@lastBstart < @lastAstart), 1, 0),
IF(@inA AND (@lastAstart < @lastBstart), 1, 0)
) as fullyEnclosed,
isStart,
IF(name='a',@inA:=isStart,0),
IF(name='b',@inB:=isStart,0),
IF(name='a',IF(isStart,@lastAstart:=t,@lastAend:=t),0),
IF(name='b',IF(isStart,@lastBstart:=t,@lastBend:=t),0)
FROM (
(SELECT *, UNIX_TIMESTAMP(start) as t, 1 as isStart FROM `shifts` WHERE name IN ('a', 'b'))
UNION ALL
(SELECT *, UNIX_TIMESTAMP(end) as t, 0 as isStart FROM `shifts` WHERE name IN ('a', 'b'))
ORDER BY t
) as sae
) AS final WHERE NOT isStart AND NOT fullyEnclosed;
基本思想是按时间列出两次表格,以便每条记录出现两次。一次为开始时间,然后为结束时间。然后我使用用户定义的变量来跟踪状态,同时遍历记录并返回“结束时间”记录,其中开始时间和结束时间根据重叠间隔进行调整。
只有假设是人x的间隔与同一个人的另一个间隔没有重叠。
很少有案例及其结果:
< ( > )
< > ( )
( < ) ( > )
( ) < > ( )
< ( ) > // for this and similar cases only last part of interval is returned
< >
( < ) ( ) ( ) ( > ) // like so
( ) < > ( )
我必须使用unix时间戳,因为我的mysql服务器无法在用户定义的变量中保存的DATETIME与其他东西之间进行比较。
它在没有任何连接的单次传递中完成,所以它应该花费O(N)时间。 它不能检索由人B的封闭间隔切出的人A间隔的所有部分。 它使用MySQL特定的功能。
答案 3 :(得分:0)
作为参考,我最近使用了一段代码。它可用于检查重叠的日期范围。它是用Ruby on Rails编写的,但这个想法(SQL语句)可以很容易地翻译成其他语言)
class Absence
named_scope :overlaps, lambda { |start, ende| {
:conditions =>
[" absences.start_date BETWEEN :start AND :end " +
"OR absences.end_date BETWEEN :start AND :end " +
"OR :start BETWEEN absences.start_date AND absences.end_date " +
"OR :end BETWEEN absences.start_date AND absences.end_date ",
{:start => start, :end => ende } ]
}}
end
与命名范围一样,此范围可以与任何其他范围一起重复使用。
user = User.find(...)
today = Date.today
confirmed_absences = user.absences.confirmed.overlaps(today.beginning_of_month, today.end_of_month).count