过去几天我一直在努力想出解决我的建模问题的方法。
我有实体 Event 它将有 1 个或多个 EventDay(s),这将代表给定日期中的连续时间段。例如活动 A 有 2 个活动日:
然后我有 User,他可以设置自己的 Schedule,对于一周中的任何一天,它应该是 1 个或多个连续的时间段。这表示他有空参加活动的时间。例如用户 B 有以下时间表:
我想要实现的是获取一个 User 可以参与的所有 Events 的列表,按照与用户的日程安排匹配的 EventDays 排名,以及所有活动天数的一些统计数据(例如,所有天的总小时数,而不仅仅是与用户的日程安排相匹配的小时数)。
一个很好的补充是能够按一个或多个工作日过滤事件。 (例如,我正在寻找只有周一和周二有活动日的活动)
首先我会提到时间段必须是 30 分钟的倍数——因此,在数据库中我将小时 00:00 存储为整数 0,00:30 存储为整数 1,依此类推直到 24:00 作为 int 48
活动
id | 姓名 |
---|---|
1 | 事件A |
活动日
id | event_id | 约会 | 开始于 | 结束于 |
---|---|---|---|---|
1 | 1 | 10.10.2000 | 20 | 35 |
2 | 1 | 11.10.2000 | 19 | 24 |
时间表
id | user_id | 天 | 开始于 | 结束于 |
---|---|---|---|---|
1 | 1 | 0 | 16 | 30 |
2 | 1 | 0 | 34 | 38 |
3 | 1 | 1 | 20 | 40 |
4 | 1 | 2 | 24 | 27 |
5 | 1 | 2 | 30 | 34 |
6 | 1 | 2 | 40 | 45 |
这里的日列在 0..6 范围内,代表星期几。
为了得到想要的结果,我提出了以下查询:
SELECT
event.id,
SUM(unfiltered_event_day.ending_at - unfiltered_event_day.starting_at) as total_event_hours,
FROM events event
INNER JOIN event_days event_day ON event.id = event_day.event_id
INNER JOIN event_days unfiltered_event_day ON event.id = unfiltered_event_day.event_id
INNER JOIN schedules schedule ON EXTRACT(ISODOW FROM event_day.date) - 1 = schedule.day
WHERE
schedule.user_id = :userId AND
EXTRACT(ISODOW FROM event_day.date) - 1 in :listOfdays AND
event_day.starting_at >= schedule.starting_at AND
event_day.ending_at <= schedule.ending_at
GROUP BY event.id
ORDER BY count(event.id) DESC, MIN(event_day.date)
EXTRACT(ISODOW FROM event_day.date) - 1 从日期中获取星期几
这种方法在性能方面有什么好处吗?我已经尝试了一些其他方法来对此建模,但这个似乎是性能最高的。
另一种方法是使用一个只读表,其中包含给定日期内所有可能的时间段组合(00:00-00:30、00:00-01:00、...、23:30-24 :00),以及它和User之间以及它和Event之间的m:n关系。这里的想法是我会双重加入时间段表,但因为它是只读的,所以它不会那么昂贵,因为它总是有一个相对较小的尺寸。
你们看到我的方法有什么缺点或改进吗?我真的很难全神贯注于建模这个