在关系数据库中存储事件发生的星期几的最佳方法是什么?

时间:2008-11-24 04:36:09

标签: database-design

我们正在为学校编写记录管理产品,其中一项要求是管理课程安排的能力。我没有看过我们如何处理这个问题的代码(我现在正处于一个不同的项目中),但是我开始想知道如何最好地处理这个要求的一个特定部分,即如何处理这个事实每个课程可以在一周中的一天或多天举行,以及如何最好地将这些信息存储在数据库中。为了提供一些上下文,一个简单的Course表可能包含以下列:

Course          Example Data
------          ------------

DeptPrefix      ;MATH, ENG, CS, ...
Number          ;101, 300, 450, ...
Title           ;Algebra, Shakespeare, Advanced Data Structures, ...
Description     ;...
DaysOfWeek      ;Monday, Tuesday-Thursday, ...
StartTime       
EndTime           

我想知道的是,在这个(人为的)示例中处理DaysOfWeek列的最佳方法是什么?我遇到的问题是,这是一个多值的领域:也就是说,你可以在一周中的任何一天开设一门课程,并且可以在一天以上的时间内完成相同的课程。我知道某些数据库本身支持多值列,但假设数据库本身不支持它,是否有“最佳实践”来处理这个问题?

到目前为止,我已经提出了以下可能的解决方案,但我想知道是否有人有更好的解决方案:

可能的解决方案#1:将DaysOfWeek视为位字段

这是我头脑中的第一件事(我不确定这是不是一件好事......)。在此解决方案中,DaysOfWeek将被定义为一个字节,前7位将用于表示星期几(每天一位)。 1位表示课程在一周的相应日期举行。

优点:易于实施(应用程序可以处理位操作),适用于任何数据库。

缺点:更难编写使用DaysOfWeek列的查询(尽管您可以在应用程序级别处理此问题,或者在数据库中创建视图和存储过程以简化此操作) ,打破了关系数据库模型。

可能的解决方案#2:将DaysOfWeek存储为字符串

这与使用位字段的方法基本相同,但是不是处理原始位,而是为一周中的每一天分配一个唯一的字母,而DaysOfWeek列只存储一系列字母指示什么日子一个课程举行。例如,您可以将每个工作日与单字符代码关联,如下所示:

Weekday      Letter
-------      ------

Sunday       S
Monday       M
Tuesday      T
Wednesday    W
Thursday     R
Friday       F
Saturday     U

在这种情况下,周一,周二和周五举行的课程'MTF'的价值为DaysOfWeek,而仅在周三举行的课程的价值为DaysOfWeek 'W'

优点:在查询中更容易处理(即您可以使用INSTR或其等价物来确定某一类是否在某一天举行)。适用于任何支持INSTR或等效功能的数据库(大多数情况下,我猜...)。同样更友好,一目了然,一目了然查看使用DaysOfWeek列的查询中发生了什么。

缺点:唯一真正的“骗局”是,就像位域方法一样,这会通过在单个字段中存储可变数量的值来打破关系模型。

可能的解决方案#3:使用查找表(丑陋)

另一种可能性是创建一个新表,该表存储一周中所有日期的唯一组合,并将Course.DaysOfWeek列简单地作为此查找表中的外键。然而,这个解决方案似乎是最不优雅的解决方案,我只考虑它,因为它似乎是关系方式 TM 来做事。

优点:从关系​​数据库的角度来看,这是唯一的“纯粹”解决方案。

缺点:它不够优雅和繁琐。例如,您将如何设计用户界面以将相应的工作日分配到查找表周围的给定课程?我怀疑用户想要处理“星期日”,“星期日,星期一”,“星期日,星期一,星期二”,“星期日,星期一,星期二,星期三”等等的选择,等等......

其他想法?

那么,是否有更优雅的方法来处理单个列中的多个值?或者提议的解决方案是否足够?对于它的价值,我认为我的第二个解决方案可能是我在此概述的三个可能解决方案中最好的,但我很想知道是否有人有不同的意见(或者确实是完全不同的方法)。

6 个答案:

答案 0 :(得分:18)

如果我们使用bit选项,我认为编写查询很困难。只需使用简单的二进制数学我认为这是最有效的方法。就个人而言,我一直这样做。看看:

 sun=1, mon=2, tue=4, wed=8, thu=16, fri=32, sat=64. 

现在,说这个课程是星期一,星期三和星期五。在数据库中保存的值为42(2 + 8 + 32)。然后你可以在周三选择课程:

select * from courses where (days & 8) > 0

如果你想要写星期四和星期五的课程你会写:

select * from courses where (days & 48) > 0

这篇文章是相关的:http://en.wikipedia.org/wiki/Bitwise_operation

你可以把星期几的数字作为代码中的常量,它就足够清楚了。

希望它有所帮助。

答案 1 :(得分:17)

我会避免纯度感的字符串选项:它增加了一个你不需要的额外编码/解码层。在国际化的情况下,它也可能搞砸你。

由于一周中的天数是7,我会保留七列,也许是布尔值。这也将有助于后续查询。如果该工具曾在不同日期工作周开始的国家使用,那么这也很有用。

我会避免查找,因为这会过度规范化。除非您的查询项目不明显或可能发生变化,否则这样做太过分了。在星期几的情况下(例如,与美国不同),我会用固定的套装安然入睡。

考虑到数据域,我认为bitfield不会为您节省大量空间,只会让您的代码变得更复杂。

最后,关于这个领域的一个警告:很多学校都会按照他们的日程安排做奇怪的事情,他们“交换日子”在假期期间平衡每个类型的相同数量的工作日。我不清楚你的系统,但也许最好的办法是存储一个预计课程实际日期的表格。这样,如果一周内有两个星期二,老师可以两次出现而获得报酬,被取消的星期四的老师不会付钱。

答案 2 :(得分:7)

可能的#4:为什么它需要是一个列?您可以为表中的每一天添加7位列。针对它编写SQL很简单,只需在您选择的列中测试1即可。从数据库中读取的应用程序代码只是将其隐藏在交换机中。我意识到这不是正常的形式,我通常会花费相当多的时间来尝试从之前的程序员那里撤消这些设计,但我有点怀疑我们是否会在短期内添加第八天。

要评论其他解决方案,如果遇到查找表,我可能会呻吟。我的第一个倾向是带有一些自定义数据库函数的位字段,可以帮助您轻松地针对该字段编写自然查询。

我很想读一些人们想出的其他建议。

编辑:我应该添加#3并且上面的建议更容易添加索引。我不确定如何编写一个SQL查询,例如“让我上周四的所有课程”来查找不会导致表扫描的#1或#2查询。但今晚我可能只是昏暗。

答案 3 :(得分:4)

第3号解决方案似乎与我的建议最接近。查找表的概念的扩展。每门课程都有一个或多个课程。创建一个包含属性的会话表:course_id,day,time,lecturer_id,room_id等。

您现在可以为每个课程的每个课程分配不同的讲师或房间,假设您可能希望稍后存储此数据。

如果您正在考虑最佳数据库设计,则用户界面问题无关紧要。您始终可以创建用于显示数据的视图,并且为了捕获数据,您的应用程序可以处理为每个课程捕获许多会话并将其添加到数据库的逻辑。

表格的含义会更清晰,这使得长期维护更容易。

答案 4 :(得分:3)

如果您选择一个或两个,您的表格将不会是1NF(第一范式),因为它包含一个多值列。

尼古拉斯有一个很好的主意,虽然我不同意他的想法打破了第一个正常形式:数据实际上并没有重复,因为每一天都是独立存储的。 唯一的问题是你必须检索更多列。

答案 5 :(得分:1)

如果表演是一个问题,我会建议更清洁的#3。

将您的课程链接到“日程表”。

又与days_in_schedule表相关联。

days_in_schedule表的列为schedule_name,日期为in_schedule_day。在该时间表中为每个有效日期添加一行。

你需要一些时间来运行一些聪明的程序来填充表格但是一旦这样做了 灵活性是值得的。

您不仅可以应对“仅限星期五的课程”,还可以应对“仅限第一学期”,“第三学期翻修实验室”和“加拿大分校有不同的假期安排”。

其他可能的疑问是“从4月1日开始的20天课程的结束日期”,其中“安排冲突最多”。 如果你真的擅长SQL,你可以问“xxx课程中有哪些日子可以开放给已经预订了yyy课程的学生” - 我觉得这是你提出的系统真正的学习成果。