设计简单的教师 - 学科 - 学生 - 批处理关系数据库的方式是什么?

时间:2014-07-13 15:44:34

标签: mysql database-design relational-database constraints

条件

  1. 许多教师对一个学科的关系,即一个学科可以由多个教师教授,但一个教师只能教一个科目

  2. 许多学生与很多学科的关系,即很多学生可以参加一个共同的科目,一个学生可以参加很多科目。

  3. 许多学生与很多批次的关系。

  4. 一次不能保留两批,因此需要在批处理表中使用唯一的日期字段。

  5. 许多批次与一个主题关系,即每批次只教授一个主题。 但在其他批次中,可以重复上一批中教授的相同科目。

  6. 最后一个条件是给我一个问题,那就是很多批次与一个教师的关系 教师可以分多批教学,每批只教一名教师。

  7. 我的初步方法如下

    teacher table
    -----------------------
    id(PK)   name   email   subject_id(FK to subject.id)
    
    
    
    subject table
    -----------------------
    id(PK)   name   description
    
    
    
    student table
    ----------------------
    id(PK)   name   location
    
    
    
    batch table
    ----------------------
    id(PK)   venue   teacher_id(FK to teacher.id)   date(unique)
    
    
    
    student-batch table
    -----------------------
    id(PK)   batch_id(FK to batch.id)   student_id(FK to student.id)
    

    并且需要获取信息,让我们说出批次的ID,教师的姓名,学生的姓名。

    但是,在将教师分配到批次时会出现问题,在每批中只教授一个特定的科目,而且一名教师也不能教授多个科目。

1 个答案:

答案 0 :(得分:1)

您缺少一个关联主题和学生的表格(按照第2点):

// student [student_id] takes subject [subject_id]
takes(student_id, subject_id)

请注意,每个基表都有一个关联业务情境语句的关联语句模板,由列名称参数化 - 其(特征)谓词。使谓词为true的行进入表中。请注意,表定义看起来像是谓词的简写。

// teacher [id] named [name] with email [email] teaches subject [subject_id]
teacher(id, name, email, subject_id)

// subject [id] named [name] is [description]
subject(id, name, description)

// student [id] named [name] lives at [location])
student(id, name, location)

// batch [id] at venue [venue] was taught by teacher [teacher_id] on date [date]
batch(id, venue, teacher_id, date)

// student-batch [id] reports student [student_id] being in batch [batch_id]
student-batch(id, student_id, batch_id)
// CHECK student [student_id] takes the subject that is taught by the teacher of batch [batch_id]
  

但是,在将教师分配到批次时会出现问题,在每批中只教授一个特定的科目,而且一名教师也不能教授多个科目。

由于你似乎对此感到困惑,我将根据我们如何推理表,约束和查询设计来推导它。表达所需约束的一种方法似乎是上面注释的CHECK。

要在SQL中表达任何表,约束或查询,我们首先要确定它的谓词。然后我们可以将谓词转换为速记。然后我们可以将速记转换为SQL。

谓词:

student [student_id] takes the subject that is taught by the teacher of batch [batch_id]

使用基表谓词:

FOR SOME k.*, t.*, b.* (
    student_id = k.student_id AND batch_id = b.bid
AND student [k.student_id] takes subject [k.subject_id]
AND teacher [t.id] named [t.name] with email [t.email] teaches subject [t.subject_id] 
AND batch [b.id] at venue [b.venue] was taught by teacher [b.teacher_id] on date [b.date]
AND [k.subject_id] = [t.subject_id]
AND [t.id] = [b.teacher_id])

使用短线:

FOR SOME k.*, t.*, b.* (
    student_id = k.student_id AND batch_id = b.bid
AND takes(k.student_id, k.subject_id)
AND teacher(t.id, t.name, t.email, t.subject_id)
AND batch(b.id, b.venue, b.teacher_id, date)
AND k.subject_id = t.subject_id
AND t.id = b.teacher_id)

在FROM中,每个(可能是隐式的)别名表示一个类似于给定基表名称和/或子查询的表,但每个列的值和值都是一样的。谓词已重命名为别名

通过在SQL中连接谓词的表,我们得到满足两个谓词的AND的行。如果我们想要满足条件AND的行,那么我们在SQL中使用ON或WHERE。

SELECT子句返回行,其中返回的(未标记的)列的FOR SOME值为满足FROM谓词的虚线列的函数。

SQL:按表格替换语句,按JOIN或ON或WHERE替换语句,外部FOR SOME& SELECT的存在:

SELECT t.student_id AS student_id, b.bid AS batch_id
FROM takes k JOIN teacher t JOIN batch b
WHERE k.subject_id = t.subject_id
AND t.id = b.teacher_id
AND student_id = t.student_id
AND batch_id = b.id

满足两个谓词的OR的行表是其表的UNION。对于AND NOT,我们使用EXCEPT(aka MINUS)(或LEFT JOIN惯用法)。对于某些或所有列的EXISTS都无法在SQL中查询,但如果我们想知道是否有满足谓词的行,那么我们可以使用该谓词的子查询周围的EXISTS。

假设我们想要约束一个基表,以便每一行都满足某些列的谓词。即对于所有列,如果它们满足基本谓词那么它们满足查询谓词。即对于所有列,如果它们形成的行在基础中,则它在查询中。所以我们在SQL中要求NOT EXISTS(SELECT FROM FROM EXCEPT查询)。或者对于基础中的每一行,我们在SQL中要求EXISTS(查询)。

在标准SQL中,你可以创建ASSERTION CHECK(NOT EXISTS(SELECT student_id,batch_id FROM student-batch EXCEPT query))或者在CREATE TABLE学生批处理中你可以检查(EXISTS(查询))。不幸的是,MySQL或大多数DBMS都不支持这些。如果批量后INSERT到批次,则可以在触发器上要求EXISTS(查询)。或者你可以添加某些列&复合FK(外键)约束。

  

并且需要获取信息,让我们说出批次的ID,教师的姓名,学生的姓名。

现在我们正在编写一个查询。我们想要行:

FOR k.*, t.*, b.*, s.*, sb.* (
    batch = b.id AND teacher = t.name AND student = s.name
AND takes(k.student_id, k.subject_id)
AND teacher(t.id, t.name, t.email, t.subject_id)
AND batch(b.id, b.venue, b.teacher_id, b.date)
AND student(s.id, s.name, s.location)
AND student-batch(sb.id, sb.student_id, sb.batch_id)
AND k.subject_id = t.subject_id
AND t.id = b.teacher_id
AND s.id = k.student_id
AND sb.student_id = k.student_id
AND sb.batch_id = b.id
AND @date = b.date)

这看起来像具有不同返回列和添加行的约束谓词。 SQL就像直接翻译一样。我们与学生一起加入学生姓名。我们添加了一个学生批处理的连接,因为约束不处理它;使用约束查询的上下文检查是否包含student-batch(student_id,batch_id)子行。

SELECT b.id AS batch, t.name AS teacher, s.name AS student
FROM takes k JOIN teacher t JOIN batch b JOIN student s JOIN student-batch sb
WHERE ... AND @date = date

您可以尝试使用ON版本:

SELECT b.id AS Batch, t.name AS Teacher, s.name AS Student
FROM takes k
JOIN teacher t ON k.subject_id = t.subject_id
JOIN batch b ON t.id = b.teacher_id
JOIN ...
WHERE @date = b.date
相关问题