我有这个预订表结构
|ID|timeBooked | duration |
|2 |2013-05-09 11:10:00| 30 |
|1 |2013-05-09 14:40:00| 15 |
|AI| timespan | int(4) |
duration 表示持续时间(以分钟为单位)。
所以我想要的是当我
时返回这样的记录集查询2013年5月9日00:00:00至23:00:00之间的可用时段
|free_from|Free_until| Free |
|00:00:00 |11:10:00 | 1
|11:10:00 |11:40:00 | 0
|11:40:00 |14:40:00 | 1
|14:40:00 |14:55:00 | 0
|14:55:00 |23:00:00 | 1
仅用 mysql 可以吗?
好吧,纯粹的 MySQL - 只要人们喜欢这些技巧。我需要一个初始化为要显示的周期的“开始”的变量,通常类似于 now() 。
首先是测试数据:
create table bookingEvents
(id int not null primary key auto_increment,
timeBooked datetime,
duration int
);
insert into bookingEvents values (null, '2013-05-13 13:22:00', 15);
insert into bookingEvents values (null, '2013-05-13 15:10:00', 45);
insert into bookingEvents values (null, '2013-05-13 19:55:00', 30);
insert into bookingEvents values (null, '2013-05-14 03:22:00', 15);
insert into bookingEvents values (null, '2013-05-14 08:19:00', 15);
然后初始化“滑块”:
set @timeSlider='2013-05-10 00:00:00';
然后选择:
select if (d.name = 'Free', @timeSlider, b.timeBooked) as free_from,
if (d.name = 'Free', b.timeBooked, @timeSlider := b.timeBooked + interval b.duration minute) as free_until,
d.name as Free
from (select 1 as place, 'Free' as name union select 2 as place, 'Booked' as name) d
inner join bookingEvents b
having free_from < free_until
order by b.timeBooked, d.place;
结果:
+---------------------+---------------------+--------+
| free_from | free_until | Free |
+---------------------+---------------------+--------+
| 2013-05-10 00:00:00 | 2013-05-13 13:22:00 | Free |
| 2013-05-13 13:22:00 | 2013-05-13 13:37:00 | Booked |
| 2013-05-13 13:37:00 | 2013-05-13 15:10:00 | Free |
| 2013-05-13 15:10:00 | 2013-05-13 15:55:00 | Booked |
| 2013-05-13 15:55:00 | 2013-05-13 19:55:00 | Free |
| 2013-05-13 19:55:00 | 2013-05-13 20:25:00 | Booked |
| 2013-05-13 20:25:00 | 2013-05-14 03:22:00 | Free |
| 2013-05-14 03:22:00 | 2013-05-14 03:37:00 | Booked |
| 2013-05-14 03:37:00 | 2013-05-14 08:19:00 | Free |
| 2013-05-14 08:19:00 | 2013-05-14 08:34:00 | Booked |
+---------------------+---------------------+--------+
如果您有给定的结束时间戳,那么您必须将其预先设置为@timeMaximum
set @timeSlider='2013-05-10 00:00:00';
set @timeMaximum='2013-05-14 08:35:00';
select if (d.name = 'Free', @timeSlider, b.timeBooked) as free_from,
if (d.name = 'Free', b.timeBooked, @timeSlider := b.timeBooked + interval b.duration minute) as free_until,
d.name as Free
from (select 1 as place, 'Free' as name union select 2 as place, 'Booked' as name ) as d
inner join bookingEvents b
having free_from < free_until
union select @timeSlider as free_from, @timeMaximum as free_until, 'Free' as Free
from (select 1) as d
where @timeSlider < @timeMaximum
order by free_from, free_until
;
不确定如何获取空闲时间记录集,但我相信这是正确的方法:
SELECT id,
DATE_FORMAT(timeBooked, '%H:%i:%s') AS initial_time,
DATE_FORMAT(DATE_ADD(timeBooked, INTERVAL duration MINUTE), '%H:%i:%s') AS final_time,
duration
FROM your_table t1
WHERE DATE(timeBooked) = '2013-05-09'
ORDER BY t1.timeBooked ASC;
希望它能派上用场!
编辑: 被我的其他答案废弃了。只要您简单地浏览有序数据,性能就应该很好。
旧:
我认为,只要表中有合理数量的行,仅在 SQL 中,解决方案就会变得非常慢。
SQL 表本身并不能避免重叠。
我会使用这样的桌子:
CREATE TABLE bookingEvents (id int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
event ENUM('start', 'end') NOT NULL,
bookingId INT(11) NOT NULL,
eventTime DATETIME NOT NULL,
index (eventTime)
);
其中 bookingId 引用包含有关预订信息的附加表。
然后你可以这样列出:
SELECT event, eventTime
FROM bookingEvents
WHERE (date or something)
ORDER BY eventTime;
您会得到(只要预订不重叠)交替的 bookingStart 和 bookingEnd 时间,其填充方式如下
time1 time2 booked
time2 time3 free
time3 time4 booked
time4 time5 free
您可以在每个条目中使用开始/结束检查轻松检查免费和预订的比赛。
插入预订非常简单
INSERT INTO bookingEvents (event, bookingId, eventTime)
VALUES ('start', $bookingId, $timeBooked ),
('end' , $bookingId, $timeBooked + interval $length minute)
;
@flaschenpost 请用两个日期检查您的答案。我认为它没有按预期工作。 我说的是你的这个答案 设置@timeSlider='2013-05-10 00:00:00'; 设置@timeMaximum='2013-05-14 08:35:00';
选择 if (d.name = 'Free', @timeSlider, b.timeBooked) 作为 free_from, if (d.name = 'Free', b.timeBooked, @timeSlider := b.timeBooked + 间隔 b.duration 分钟) as free_until, d.name 为免费 from (选择 1 作为地点,“免费”作为名称 union 选择 2 作为地点,“预订”作为名称) as d 内部连接 bookingEvents b 有 free_from < free_until union select @timeSlider as free_from, @timeMaximum as free_until, 'Free' as Free from (select 1) as d where @timeSlider < @timeMaximum
按 free_from、free_until 排序;
不工作。总是给出不变的答案