如何构建数据库以避免表中的重复
Posted
技术标签:
【中文标题】如何构建数据库以避免表中的重复【英文标题】:How to structure the database to avoid duplicates in a table 【发布时间】:2020-11-13 12:07:22 【问题描述】:我正在做这个练习,我必须建立一个 sql 数据库 (mysql) 来存储教师提供的私人课程的信息。 这些是规则:
从周一到周五 (15-19) 只有一个预定义周的时段 每位教师可教授一门或多门课程 每门课程可由多名教师教授 一个用户只能在选定的小时内预订一堂课 一位教师在选定的小时内只能预订一节课我是这样实现的:
USER(Name, Surname, Email (PK), Password)
TEACHER(Name, Surname, Email (PK), Password)
COURSE(Title (PK))
SLOTTIME(Day (PK), Hour (PK))
TEACHES(EmailTeacher, TitleCourse) all attributes are PK, FK(EmailTeacher -> Teacher, TitleCourse -> Course)
BOOKING(EmailUser, EmailTeacher, TitleCourse, Day, Hour) all attributes are PK, FK((EmailUser -> User),
(EmailTeacher, TitleCourse -> Teaches), (Day, Hour -> SlotTime))
这个解决方案给我带来了两个问题,或者至少是我发现的问题:
-
我可以在同一天同一时间为同一用户预订不同的老师和不同的课程
我可以让同一用户在同一天同一时间向同一位老师预订不同的课程
这是一个例子:
BOOKING('raul@gmail.com', 'michael@gmail.com', 'Database I', 'Monday', 16) // FIRST INSERT
BOOKING('raul@gmail.com', 'anthony@gmail.com', 'Algorithms', 'Monday', 16) // DIFFERENT TEACHER AND COURSE
BOOKING('raul@gmail.com', 'michael@gmail.com', 'Database II', 'Monday', 16) // SAME TEACHER AND DIFFERENT COURSE
我想要获得的是一个遵守上述规则的表格,但我不知道如何实现它。
【问题讨论】:
你考虑过唯一性约束吗? 主键和唯一约束有什么区别? 就个人而言,我觉得你对PK的选择并不令人满意。 @Raul 在 PK 中,表达式的任何部分都不能为空。 @Akina 所有的表属性都不为空 【参考方案1】:我会说您需要一个用于教师预订的表格,该表格对教师和白天的时间有独特的限制。该限制将阻止教师一次预订超过一小时。是否希望它成为 PK 取决于您的偏好,我个人不喜欢复合约束(PK 在语义上也是唯一约束,但唯一约束并不总是需要是 PK)。
BOOKING(EmailTeacher (PK), Day(PK), Hour(PK), TitleCourse) or
BOOKING(ID (PK), EmailTeacher, Day, Hour, TitleCourse)
通过此设置,我会将您的预订表重命名为 SUBSCRIPTION,以便为两个不同的实体提供两个不同的名称(并使有关它们的对话更容易)。预订应与订阅相关联,或者来自教师或教书(这引发了一个哲学问题;))。
在 SUBSCRIPTION 表上,您需要对 (user,day, hour) 设置唯一约束,以防止用户在同一时间间隔内预订多个时段。
SUBSCRIPTION(EmailUser(PK), EmailTeacher(PK), Day(PK), Hour(PK)) or
SUBSCRIPTION(EmailUser(PK), BookingId(PK))
【讨论】:
在SUBSCRIPTION
中,如果我将(用户、日期、小时)设为唯一,问题仍然存在,因为我可以有两个用户和同一个老师。相反,使(老师,天,小时)唯一我可以让用户一次只与一位老师一起预订,反之亦然,一位老师一次与一名学生一起预订。但我不知道它是否 100% 正确。
您没有说课程仅限于一名学生(用户)。在这种情况下,在订阅中,您应该使 bookingId(无论是复合版本还是简单版本)都是唯一的。【参考方案2】:
先梳理逻辑设计,再细化。
-- Teacher TCH exists.
--
teacher TCH
PK TCH
-- Course CRS exists.
--
course CRS
PK CRS
-- Time slot TIM exists.
--
slot TIM
PK TIM
-- Teacher TCH teaches course CRS.
--
teacher_course TCH, CRS
PK TCH, CRS
FK1 TCH REFERENCES teacher TCH
FK2 CRS REFERENCES course CRS
-- Teacher TCH booked time slot TIM for course CRS.
--
teacher_slot_course TCH, TIM, CRS
PK TCH, TIM
SK TCH, TIM, CRS
FK1 TCH, CRS REFERENCES teacher_course TCH, CRS
FK2 TIM REFERENCES slot TIM
-- Student (user) USR exists.
--
user USR
PK USR
-- Student USR signed-up for course CRS.
--
user_course USR, CRS
PK USR, CRS
FK1 USR REFERENCES user USR
FK2 CRS REFERENCES course CRS
-- Student USR booked time slot TIM
-- for course CRS with teacher TCH.
--
user_slot_course_teacher USR, TIM, CRS, TCH
PK USR, TIM
FK1 USR, CRS REFERENCES
user_course USR, CRS
FK2 TCH, TIM, CRS REFERENCES
teacher_slot_course TCH, TIM, CRS
注意:
All attributes (columns) NOT NULL
PK = Primary Key
AK = Alternate Key (Unique)
SK = Proper Superkey (Unique)
FK = Foreign Key
【讨论】:
这很好用,但与上面第一个答案的版本相比,我还不确定一件事。我打算在Java应用程序中使用这个数据库,具有多个表的架构不会使其运行速度变慢,例如输入用户预订吗?第二个问题:),如果当我取消预订时,我想将此数据保留在数据库中,最好的方法是什么,我曾想过将其插入仅包含“旧”数据的表中,但也许有一些不浪费内存的方法。 @Raul:简短回答:不。 “额外表”user_course
是不同业务逻辑的结果——要求学生在预订该课程的课程之前先注册该课程。在逻辑设计期间专注于感知到的性能问题会导致各种麻烦。此外,您所指的答案对各种逻辑错误都是开放的,主要是由于“......不喜欢复合约束......”。甚至不确定这意味着什么。看看:***.com/questions/14588304/…以上是关于如何构建数据库以避免表中的重复的主要内容,如果未能解决你的问题,请参考以下文章
如何将数据从 PySpark 持久化到 Hive - 避免重复