条件
许多教师对一个学科的关系,即一个学科可以由多个教师教授,但一个教师只能教一个科目
许多学生与很多学科的关系,即很多学生可以参加一个共同的科目,一个学生可以参加很多科目。
许多学生与很多批次的关系。
一次不能保留两批,因此需要在批处理表中使用唯一的日期字段。
许多批次与一个主题关系,即每批次只教授一个主题。 但在其他批次中,可以重复上一批中教授的相同科目。
最后一个条件是给我一个问题,那就是很多批次与一个教师的关系 教师可以分多批教学,每批只教一名教师。
我的初步方法如下
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,教师的姓名,学生的姓名。
但是,在将教师分配到批次时会出现问题,在每批中只教授一个特定的科目,而且一名教师也不能教授多个科目。
答案 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