【问题标题】:What is the way of designing a simple teacher-subject-student-batch relational database?设计一个简单的教师-学科-学生-批次关系数据库的方法是什么?
【发布时间】:2014-09-03 15:42:55
【问题描述】:

条件是

  1. 多位教师与一门学科的关系,即一门学科可以由多位教师教授,但一位教师只能教授一门学科

  2. 多学生多学科的关系,即多学生可以选一门共同的学科,一个学生可以选多门学科。

  3. 多学生多批次关系。

  4. 不能同时保存两个批次,所以批次表中需要一个唯一的日期字段。

  5. 多批次与一门学科的关系,即每批次仅教授一门学科。 但在其他批次中,之前批次所教的相同科目可以重复。

  6. 最后一个条件是给我一个问题,即多批次到一位老师的关系,即 是一个老师可以教多个批次,并且每个批次只有一个老师。

我最初的方法如下

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、教师姓名、学生姓名。

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

【问题讨论】:

  • 在这种情况下什么是batch
  • Batch就像实际的教学过程,比如说sam老师在欧洲教学,2014年8月1日,就像一个教学活动。
  • 看起来很接近。你需要一个teacher-subject 表而不是把科目放在教师记录中;一个老师可以教不止一门课。还要从batch 中删除teacher_id,改用teacher-batch 表。
  • 不行,一个老师只能教一门课
  • 是的,一门学科可以由多个教师教授,这就是为什么教师与学科之间存在多对一关系。

标签: mysql database-design relational-database constraints


【解决方案1】:

您缺少关联科目和学生的表格(根据第 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 中,每个(可能是隐式的)别名代表一个类似于给定基表名称和/或子查询的表,但其值和谓词中的每一列都重命名为 aliascolumn。

我们通过在 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

【讨论】:

  • 非常好的描述。但是如何插入数据呢?如何根据phpmyadmin中同一张表中另一个字段的外键选项设置外键选项?如果不可能,当我在插入数据后单击go 时如何获取错误消息?请查看this 我发布但没有答案的问题。
猜你喜欢
  • 2011-12-15
  • 1970-01-01
  • 2014-11-09
  • 2018-08-26
  • 1970-01-01
  • 1970-01-01
  • 2019-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多