如何构建数据库以避免表中的重复

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 - 避免重复

如何避免 writeToBq 步骤中数据流束管道中的重复?

如何根据另一个表中的值创建重复记录

如何避免在回发时从 asp.net 重复输入?

数据库缓慢检索/更新/插入问题,每个表中有超过 500 万条记录

如何检查一个值是不是已经存在以避免重复?