简体   繁体   English

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

[英]What's the best way to store the days of the week an event takes place on in a relational database?

We're writing a records management product for schools and one of the requirements is the ability to manage course schedules. 我们正在为学校编写记录管理产品,其中一项要求是能够管理课程表。 I haven't looked at the code for how we deal with this (I'm on a different project at the moment), but nonetheless I started wondering how best to handle one particular part of this requirement, namely how to handle the fact that each course can be held one or more days of the week, and how best to store this information in the database. 我没有看过如何处理此代码(目前我在一个不同的项目中),但是我开始想知道如何最好地处理此要求的一个特定部分,即如何处理以下事实:每门课程每周可以举行一或几天,以及如何最好地将这些信息存储在数据库中。 To provide some context, a bare-bones Course table might contain the following columns: 为了提供一些背景信息,“简明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           

What I'm wondering is, what is the best way to handle the DaysOfWeek column in this (contrived) example? 我想知道的是,在此(人为)示例中处理DaysOfWeek列的最佳方法是什么? The problem I'm having with it is that is a multi-valued field: that is, you can have a course on any day of the week, and the same course can take be held on more than one day. 我遇到的问题是,它是一个多值字段:也就是说,您可以在一周的任何一天进行一门课程,而同一门课程可以在一天以上进行。 I know certain databases natively support multi-value columns, but is there a "best practice" to handle this assuming the database doesn't natively support it? 我知道某些数据库本身支持多值列,但是假设数据库本身不支持多值列,是否有“最佳实践”来处理呢?

I've come up with the following possible solutions so far, but I'm wondering if anyone has anything better: 到目前为止,我已经提出了以下可能的解决方案,但是我想知道是否有人有更好的选择:

Possible Solution #1: Treat DaysOfWeek as a bit field 可能的解决方案1:将DaysOfWeek视为位字段

This was the first thing that popped into my head (I'm not sure if that's a good thing or not...). 这是突然出现在我脑海中的第一件事(我不确定那是否是好事...)。 In this solution, DaysOfWeek would be defined as a byte, and the first 7 bits would be used to represent the days of week (one bit for each day). 在此解决方案中, DaysOfWeek将被定义为一个字节,并且前7位将用于表示星期几(每天1位)。 A 1 bit would indicate that a class was held on corresponding day of the week. 1位表示该课程在一周的相应日期举行。

Pros : Easy to implement (the application can deal with the bit manipulations), works with any database. 优点 :易于实现(应用程序可以处理位操作),可以与任何数据库一起使用。

Cons : Harder to write queries that use the DaysOfWeek column (although you could deal with this at the application level, or create views and stored procedues in the database to simplify this), breaks relational database model. 缺点 :难以编写使用DaysOfWeek列的查询(尽管您可以在应用程序级别处理此问题,或者在数据库中创建视图和存储过程来简化此操作),这会破坏关系数据库模型。

Possible Solution #2: Store DaysOfWeek as a string of characters 可能的解决方案2:将DaysOfWeek存储为字符串

This is essentially the same approach as using a bit field, but instead of dealing with raw bits, you assign a unique letter to each day of the week, and the DaysOfWeek column just stores a sequence of letters indicating what days a course is held on. 这本质上与使用位字段的方法相同,但是无需处理原始位,而是为一周中的每一天分配一个唯一的字母,并且DaysOfWeek列仅存储一系列字母,指示课程的开设日期。 For example, you might associate each weekday with a single-character code as follows: 例如,您可以将每个工作日与单个字符代码相关联,如下所示:

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

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

In this case, a course held on Monday, Tuesday, and Friday would have have the value 'MTF' for DaysOfWeek , while a class held only on Wednesdays would have a DaysOfWeek value of 'W' . 在这种情况下,当然举行周一,周二和周五将有有值'MTF'DaysOfWeek ,而只有在周三召开班将有DaysOfWeek的值'W'

Pros : Easier to deal with in queries (ie You could use INSTR , or its equivalent, to determine if a class is held on a given day). 优点 :更易于处理查询(即,您可以使用INSTR或类似的方法来确定某个课程是否在指定的日期举行)。 Works with any database that supports INSTR or an equivalent function (most, I would guess...). 可与支持INSTR或等效功能的任何数据库一起使用(我想大多数是...)。 Also friendlier to look at, and easy to see at a glance what is happening in queries that use the DaysOfWeek column. 使用DaysOfWeek列时,查询起来也更加友好,一目了然。

Cons : The only real "con" is that, like the bitfield approach, this breaks the relational model by storing a variable number of values in a single field. 缺点 :唯一真正的“ 缺点 ”是,就像位域方法一样,这通过在单个字段中存储可变数量的值来破坏关系模型。

Possible Solution #3: Use a Lookup Table (ugly) 可能的解决方案#3:使用查找表(难看)

Another possibility would be to create a new table that stores all the unique combinations of days of the week, and have the Course.DaysOfWeek column simply be a foreign key into this lookup table. 另一种可能性是创建一个新表,该表存储一周中各天的所有唯一组合,并将Course.DaysOfWeek列简单地用作此查找表的外键。 However, this solution seems like the most inelegant one, and I only considered it because it seemed like the The Relational Way TM to do things. 但是,这种解决方案似乎是最精致的解决方案,我之所以只考虑它,是因为它看起来像是The Relational Way TM做事情。

Pros : It's the only solution that is "pure" from a relational database point of view. 优点 :从关系数据库的角度来看,这是唯一“纯”的解决方案。

Cons : It's inelegant and cumbersome. 缺点 :笨拙而且繁琐。 For example, how would you design the user interface for assigning corresponding weekdays to a given course around the lookup table? 例如,您将如何设计用于在查找表周围为给定课程分配相应工作日的用户界面? I doubt a user wants to deal with choices alongs the lines of "Sunday", "Sunday, Monday", "Sunday, Monday, Tuesday", "Sunday, Monday, Tuesday, Wednesday", and so on... 我怀疑用户是否想按照“星期日”,“星期日,星期一”,“星期日,星期一,星期二”,“星期日,星期一,星期二,星期三”等来处理选择……

Other Ideas? 还有其他想法吗?

So, is there a more elegant way to handle multiple values in a single column? 那么,有没有更优雅的方式可以在单个列中处理多个值? Or would one the proposed solutions suffice? 或提议的解决方案之一就足够了吗? For what it's worth, I think my second solution is probably the best of the three possible solutions that I outlined here, but I'd be curious to see if someone has a different opinion (or indeed a different approach altogether). 对于它的价值,我认为我的第二个解决方案可能是我在这里概述的三种可能的解决方案中最好的,但是我很想知道某人是否有不同的看法(或者实际上是完全不同的方法)。

I don't think it's hard to write queries if we use the bit option. 如果使用bit选项,我认为写查询并不困难。 Just use simple binary math. 只需使用简单的二进制数学即可。 I think it's the most efficient method. 我认为这是最有效的方法。 Personally, I do it all the time. 就个人而言,我一直都这样做。 Take a look: 看一看:

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

Now, say the course is held on mon, wed and fri. 现在,假设课程在星期一,星期三和星期五举行。 the value to save in database would be 42 (2+8+32). 保存在数据库中的值为42(2 + 8 + 32)。 Then you can select courses on wednesday like this: 然后,您可以像这样在星期三选择课程:

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

if you want courses on thu and fri you would write: 如果您想学习星期四和星期五的课程,您可以写:

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

this article is relevant: http://en.wikipedia.org/wiki/Bitwise_operation 本文是相关的: http : //en.wikipedia.org/wiki/Bitwise_operation

you can put days of week numbers, as constants in your code and it will be clear enough. 您可以将星期几作为常量输入代码中,这样就足够清楚了。

Hope it helps. 希望能帮助到你。

I would avoid the string option for the sense of purity: it adds an extra layer of encoding/decoding that you do not need. 从纯粹的意义上讲,我会避免使用string选项:它增加了您不需要的额外编码/解码层。 It may also mess you up in the case of internationalization. 在国际化的情况下,它也可能使您感到困惑。

Since the number of days in a week is 7, I would keep seven columns, perhaps boolean. 由于一周中的天数是7,因此我将保留7列,可能是布尔值。 This will also facilitate subsequent queries. 这也将便于后续查询。 This will also be useful if the tool is ever used in countries where the workweek starts on different days. 如果该工具曾经在工作周在不同日期开始的国家/地区使用过,则这也将很有用。

I would avoid the lookup because that would be over-normalization. 我会避免查找,因为那会过度标准化。 Unless your set of lookup items is not obvious or could possibly change, it's overkill. 除非您的查找项目集不明显或可能更改,否则它是过大的。 In the case of days-of-the-week (unlike US states, for example), I would sleep soundly with the fixed set. 在一周的几天中(例如,与美国各州不同),我会在固定的情况下安然入睡。

Considering the data domain, I don't think that a bitfield would achieve any significant space savings for you and would just make your code more complex. 考虑到数据域,我认为位域不会为您节省大量空间,只会使您的代码更复杂。

Finally, a word of warning about the domain: a lot of schools do weird things with their schedules where they "swap days" to balance out an equal number of weekdays of each type over the semester despite holidays. 最后,一个关于领域的警告:许多学校在日程安排上做一些奇怪的事情,他们“交换日”以平衡整个学期中每种类型平日的数量,尽管有节假日。 I am not clear about your system, but perhaps the best approach would be to store a table of the actual dates in which the course is expected to take place. 对于您的系统,我尚不清楚,但是最好的方法也许是存储一张预期要上课的实际日期表。 This way, if there are two Tuesdays in a week, the teacher can get paid for showing up twice, and the teacher for the Thursday that was canceled will not pay. 这样,如果一周中有两个星期二,老师可以因两次出现而获得报酬,而被取消的星期四的老师将不会获得报酬。

A possible #4: Why does it need to be a single column? 可能的#4:为什么它必须是一列? You could add 7 bit columns for each day of the week to the table. 您可以将一周中的每一天的7位列添加到表中。 Writing SQL against it is simple, just test for a 1 in the column of your choice. 用它编写SQL很简单,只需在您选择的列中测试1。 And the app code reading from the database just hides this in a switch. 从数据库读取的应用程序代码只是将其隐藏在开关中。 I realize that this is not normal form and I usually spend quite a bit of time trying to undo such designs from previous programmers, but I somewhat doubt that we're going to add an eighth day to the week any time soon. 我意识到这不是正常的形式,并且我通常花费大量时间来尝试撤消以前的程序员的此类设计,但是我有点怀疑我们是否会在不久的将来将第八天增加到一周。

To comment on the other solutions, I would probably groan if I encountered the lookup table. 要评论其他解决方案,如果遇到查找表,我可能会吟。 My first inclination as well was the bit field with a few custom database functions to help you write natural queries against that field easily. 我的第一个倾向也是具有一些自定义数据库功能的bit字段,以帮助您轻松地针对该字段编写自然查询。

I'll be curious to read some of the other suggestions that people come up with. 我很想读一下人们提出的其他一些建议。

Edit: I should add that #3 and the suggestion above are easier to add indexes to. 编辑:我应该添加#3和上面的建议更容易向其中添加索引。 I'm not sure how one could write a SQL query like "get me all classes on Thursday" for the #1 or #2 queries that wouldn't result in a table scan. 我不确定如何为不会导致表扫描的#1或#2查询编写一个SQL查询,例如“星期四给我所有课程”。 But I may just be dim tonight. 但是今晚我可能只是昏昏欲睡。

Solution number 3 seems to be closest to what I would recommend. 解决方案编号3似乎最接近我的建议。 An extension on the idea of the look up table. 查找表概念的扩展。 Each course has one or more sessions. 每门课程都有一个或多个课程。 Create a session table with attributes: course_id, day, time, lecturer_id, room_id etc. 创建一个具有以下属性的会话表:course_id,日期,时间,讲者ID,room_id等。

You now have the ability to assign a different lecturer or room to each session of each course assuming that you may want to store this data later. 现在,您可以为每个课程的每个课程分配不同的讲师或教室,前提是您以后可能希望存储此数据。

The user interface issues are not relevant if you are considering the best database design. 如果您正在考虑最佳的数据库设计,则用户界面问题并不重要。 You can always create views for displaying the data, and for capturing the data your application can take care of the logic of capturing many sessions for each course and adding them to the database. 您始终可以创建用于显示数据的视图,并为捕获数据而创建您的应用程序,可以利用为每个课程捕获许多会话并将它们添加到数据库中的逻辑。

The meaning of the tables would be clearer which makes long term maintenance easier. 这些表的含义会更清楚,这使长期维护变得更加容易。

If you choose one or two, your table will not be in 1NF (first normal form) as it contains a multi-valued column. 如果选择一个或两个,您的表将不会采用1NF(第一种范式),因为它包含一个多值列。

Nicholas has an excellent idea, although I'd disagree that his idea breaks first normal form: The data is not actually repeating, as each day is being stored independently. 尼古拉斯(Nicholas)有一个绝妙的主意,尽管我不同意他的主意打破了最初的正常形式:数据实际上并没有重复,因为每一天都是独立存储的。 The only problem with it is that you have to retrieve more columns. 唯一的问题是您必须检索更多列。

If performance is an issue I would recommend a cleaner varation of #3. 如果性能是一个问题,我建议您使用#3的变体。

Link your course to a "schedule" table. 将您的课程链接到“时间表”表。

Which is in turn linked to a days_in_schedule table. 依次链接到days_in_schedule表。

The days_in_schedule table has columns the schedule_name, and the date in_schedule_day. days_in_schedule表的列中有schedule_name和日期in_schedule_day。 With a row for each valid day in that schedule. 在该时间表中的每个有效日期都有一行。

You need some time opr some clever program to populate the table but once this is done the flexibility is worth it. 您需要一些时间或一些聪明的程序来填充表,但是一旦完成,灵活性就值得了。

You can cope not only with "course on Fridays only", but also "first semester only", "lab closed for refurbishment in third semester" and "Canadian branch has differnet holiday schedule". 您不仅可以应付“仅限周五的课程”,还可以应付“仅第一学期”,“第三学期关闭以进行翻新的实验室”和“加拿大分行的假期安排不同”的问题。

Other possible queries are "Whats the end date of 20 day course starting 1st April", which "schedules clash most". 其他可能的查询是“从4月1日开始的20天课程的结束日期是多少”,“计划最有冲突”。 If you are really good at SQL you can ask "what possible days are open in course xxx to a student who is already booked for course yyy" -- which I have the feeling is the real puprose of your proposed system. 如果您真的很擅长SQL,那么您可以问“在xxx课程中,哪些学生可能已经预订了yyy课程”,这可能是您打算的系统的真正目的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM