如何返回按实体分组的最近时间段,但仅针对最近的可用日期,而不是每个可用日期?

时间:2013-04-10 19:11:07

标签: mysql sql database

我有一个表,可以按小时为教师存储可用的约会,每个教师每天可以自由添加无限的时段(只要插槽不重叠)。示例简化结构:

CREATE TABLE time_slots (
  id int(10) unsigned NOT NULL AUTO_INCREMENT,
  teacher_id mediumint(8) unsigned NOT NULL,
  slot bigint(20) unsigned NOT NULL DEFAULT '0',
 );

slot 列存储广告位的时间戳。

如何为每位教师显示所有可用的第一个可用日期? 注意:显示给定日期的所有时段,并且不能为同一位教师显示超过一天的时间。

示例数据:

PS:使用日期时间只是为了让事情更具可读性。

+----+------------+------------------+
| id | teacher_id | slot             |
+----+------------+------------------+
| 1  | 1          | 2013-04-10 08:00 |
| 2  | 1          | 2013-04-10 09:00 |
| 3  | 1          | 2013-04-10 09:30 |
| 4  | 1          | 2013-04-11 08:00 |
| 5  | 1          | 2013-04-11 09:00 |
| 6  | 1          | 2013-04-11 10:30 |
| 7  | 2          | 2013-04-12 07:00 |
| 8  | 2          | 2013-04-12 09:00 |
| 9  | 2          | 2013-04-14 08:00 |
+----+------------+------------------+

预期结果:

假设搜索时间为: 2013-04-10 08:30 ,则返回的结果必须为:

+----+------------+------------------+
| id | teacher_id | slot             |
+----+------------+------------------+
| 2  | 1          | 2013-04-10 09:00 |
| 3  | 1          | 2013-04-10 09:30 |
| 7  | 2          | 2013-04-12 07:00 |
| 8  | 2          | 2013-04-12 09:00 |
+----+------------+------------------+
  1. 不要显示id 1,因为它已经从10月4日开始经过08:00。
  2. 不要显示ID 4,5,6,因为我们发现教师= 1的最近可用插槽是id的2和3。
  3. 不要显示id 9,因为对于教师= 2,最近的可用插槽是7和8,所以不要再返回一天。
  4. 我尝试了什么

    我很难接受查询,我刚刚接受了这个基本查询,但它没有假设只获得第一天,当然它不会返回给定日期的所有可用插槽。每个教师只返回1个插槽:

    SELECT id, teacher_id, FROM_UNIXTIME(slot)
    FROM time_slots
    WHERE slot >= [Actual timestamp]
    GROUP BY DATE(FROM_UNIXTIME(slot))
    ORDER BY slot, teacher_id ASC
    

    注意:我在这里只是为了调试而使用FROM_UNIXTIME,当然我稍后会优化索引等。

2 个答案:

答案 0 :(得分:2)

首先,您需要查询以获得每位教师最近的,因为每位教师都会有所不同。一些假的SQL在这里这样做:

SELECT
  MIN(DATE(slot)) as closestDay,
  teacher_id
FROM time_slots
WHERE slot >= NOW()
GROUP BY teacher_id

然后接受该查询并使用结果显示每天的所有可用插槽

SELECT 
   id,
   time_slots.teacher_id,
   FROM_UNIXTIMESTAMP(slot)
FROM time_slots
JOIN (
    SELECT
      MIN(DATE(slot)) as closestDay,
      teacher_id
    FROM time_slots
    WHERE slot >= NOW()
    GROUP BY teacher_id
) a
ON a.teacher_id = time_slots.teacher_id
  AND DATE(time_slots.slot) = closestDay
WHERE time_slots.slot >= NOW()

显然没有经过测试,但它应该给你一般的想法。

答案 1 :(得分:1)

无需加入:

drop table if exists time_slots;
CREATE TABLE time_slots (
  id int(10) unsigned NOT NULL AUTO_INCREMENT primary key,
  teacher_id mediumint(8) unsigned NOT NULL,
  slot datetime 
 );
insert into time_slots values 
('1','1','2013-04-10 08:00'),
('2','1','2013-04-10 09:00'),
('3','1','2013-04-10 09:30'),
('4','1','2013-04-11 08:00'),
('5','1','2013-04-11 09:00'),
('6','1','2013-04-11 10:30'),
('7','2','2013-04-12 07:00'),
('8','2','2013-04-12 09:00'),
('9','2','2013-04-14 08:00');

select * from time_slots 
where (teacher_id, date(slot)) in
(select teacher_id, date(min(slot)) from time_slots where slot >= '2013-04-10 08:30' group by teacher_id)
having slot >= '2013-04-10 08:30'
;