像@TMS,我也会使用Schedule表。我所知道的火车表不仅在平日有所不同,而且在假期和银行假期(如25.12或复活节星期一的日子)也不同。
因此,我会通过列Holiday和BankHoliday(或更好的名称,我只是德语)tinyint,0 = false,1 = true,NULL = always来扩展@ TMS的表格。这意味着,如果一列火车只在假期出现,假期中它会得到一个“1”,如果只在学校时间,它会得到一个“0”,如果假期不重要,它会变为NULL。
然后,你需要一个表CalendarDay与有趣的岁月的所有日子,你必须标记假日和银行假日。如果幸运的话,那些依赖于你所在国家的地区。在德国,你有所有区域(萨克森与巴伐利亚等不同)。
我确定在夏季和冬季有不同的时间表,并且他们每年都会更改这些时间表(2014年夏季!=冬季2013/2014!= 2013年夏季)。因此,我会添加另一个表格ScheduleTable,其中包含一个ID,一个名称,一个起始日期和一个until-date,它的ScheduleTableID也是表格Schedule中的一个额外字段。这意味着,您可以将时间表存储在下一个夏季时间表中。我会做出“直到”独家,所以2014-04-01意味着“有效期至2014年3月31日”。在必要时更容易加入连锁店。
那个日历表也可以标记DST-nightmare,例如对于较短的日期为-1,对于较长的日期为+1,对于正常日期为0。这在Schedule中也是相关的,我认为有些列车在DST-switch-days上的行为不同,所以同样的逻辑:tinyint在较短的日期为“-1”,在较长的日期为“+1”,在正常日期,如果DST对该列车无关紧要,则为NULL。
正如TMS所说,查询是BETWEEN <usertime> - interval 15 minute and <usertime> + interval 15 minute
,只针对所有calendar_day值进行扩展。
所以,当用户给出了“2014年4月25日16:30”,你应该像查询:
select Sc.*
from Schedule sc
inner join CalendarDay cd on
(
cd.day = date(<userdate>)
and (cd.holiday = sc.holiday or sc.holiday is null)
and (cd.BankHoliday = sc.BankHoliday or sc.BankHoliday is null)
and (sc.DSTSwitch = cd.DSTSwitch or sc.DSTSwitch is null)
and sc.`weekday` = weekday(cd.day)
)
inner join ScheduleTable sct on(
sct.id = sc.ScheduleTableID
and sct.from <= cd.day and sct.until > cd.day
)
where sc.`Time` between
time(<userdate>) - interval 15 minute
and time(<userdate>) + interval 15 minute
;
也许这听起来像是太多的并发症,但只要你没有ScheduleTables假期等等,这些字段不会让你失望(将它们设置为0,将ScheduleTableID设置为1,日期范围从1000年到3000年,将NULL限制在Schedule中)。但是,当他们处于桌面结构中时,对这些“问题”做出反应会更容易。