您缺少关联科目和学生的表格(根据第 2 点):
// student [student_id] takes subject [subject_id]
takes(student_id, subject_id)
请注意,每个基表都有一个关联的语句模板,用于关于业务情况的语句,由列名参数化——它的(特征)谓词。使谓词为真的行进入表中。请注意,表定义看起来像是谓词的简写。
// 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 中,每个(可能是隐式的)别名代表一个类似于给定基表名称和/或子查询的表,但其值和谓词中的每一列都重命名为 alias。column。
我们通过在 SQL 中连接谓词的表来获得满足两个谓词的 AND 的行。如果我们想要满足条件 AND 的行,那么我们在 SQL 中使用 ON 或 WHERE。
SELECT 子句返回行,其中点列的 FOR SOME 值返回的(不带点的)列等于满足 FROM 谓词的点列的函数。
SQL:用表替换语句,用 JOIN 或 ON 或 WHERE 替换语句,用 SELECT 替换外部 FOR SOME & THERE EXISTS:
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(又名 MINUS)(或 LEFT JOIN 习语)。在 SQL 中无法查询所有列的 FOR SOME 或 THERE EXISTS,但如果我们想知道是否存在满足谓词的行,那么我们可以在具有该谓词的子查询周围使用 EXISTS。
假设我们要约束一个基表,以便每一行都满足某些列的谓词。即,对于所有列,如果它们满足基本谓词,那么它们满足查询谓词。即 FOR ALL 列如果它们形成的行在基数中,那么它在查询中。因此,我们要求在 SQL 中不存在(从基本查询中选择列)。或者对于我们在 SQL 中需要 EXISTS(query) 的基础中的每一行。
在标准 SQL 中,您可以 CREATE ASSERTION CHECK(NOT EXISTS (SELECT student_id, batch_id FROM student-batch EXCEPT query)) 或在 CREATE TABLE student-batch 中您可以 CHECK(EXISTS(query))。不幸的是,MySQL 或大多数 DBMS 不支持这些。如果您在批次后插入学生批次,那么您可以要求触发该 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-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