3

考虑一个专业,比如经济学。假设学生需要选择“EC 101”或“EC 102”,但不一定要同时从该专业毕业。目前,我有两个这样的表:

课程:CourseID、CourseName

专业:MajorID、MajorName、RequiredCourseID

我如何捕捉有时专业的要求是:在我的数据库设计中要么参加课程 A 或课程 B,但不一定同时参加?

4

2 回答 2

2

架构设计

你需要重构你的表,并引入一些额外的:

  • 课程:CourseID、CourseName

  • 专业:MajorID、MajorName

  • MajorRequirements:MajorID、ReqId

  • 要求:ReqId、ReqCount

  • 必选课程选项:ReqId、CourseID

样本数据

从问题:

经济学(EC001):假设学生需要选择“EC 101”或“EC 102”,但不一定要从该专业毕业。

其他要求:

此外,主修 EC001 的学生必须修读所有三门课程 EC 200、EC 201、EC 202。

政治经济学(EC002):与经济学一样,学生需要选修“EC 101”或“EC 102”,但不一定同时选修。此外,主修 EC002 的学生必须选修 EC 200、EC 201、EC 202 三门课程中的任意两门。(而且,可能还有这里未讨论的其他课程。)

培训班

Course ID    Name
EC 101       Economics 101
EC 102       Economics 102
EC 200       Economics 200
EC 201       Economics 201
EC 202       Economics 202

专业

Major ID     Name
EC001        Economics
EC002        Political Economy

主要要求

MajorID      ReqID
EC001        R01
EC001        R02
EC002        R01
EC002        R03

要求

ReqID         ReqCount
R01           1
R02           3
R03           2

必修课程选项

ReqID         CourseID
1             EC 101
1             EC 102
2             EC 200
2             EC 201
2             EC 202
3             EC 200
3             EC 201
3             EC 202

解释

主修经济学(EC001)的人必须满足其专业的所有要求,这意味着必须满足MajorRequirements R01和R02。要满足 R01,学生必须从可用选项中选修 1 门必修课程。必修课程选项为 EC 101 和 EC 102;任何一个都足够了。要满足 R02,学生必须从可用选项中选修 3 门必修课;有三门课程(EC 200、EC 201、EC 202),因此学生必须参加所有三门课程。

同样,主修政治经济学 (EC002) 的人必须满足其专业的所有要求,这意味着必须满足 MajorRequirments R01 和 R03。和以前一样,要达到 R01,学生必须从可用选项(EC 101 或 EC 102)中选修 1 门必修课程。要达到 R03,学生必须从可用选项中选修 2 门必修课;共有三门课程(EC 200、EC 201、EC 202),学生必须至少修读三门课程中的两门。

显然,这可用于要求任何集合中的任何 M 个课程中的任何 N 个。如果主修 M 需要特定课程 C,则 MajorRequirements 表包含主修 M 的 ReqID R,ReqCount 为 1,RequiredCourseOptions 记录 R 和 C。 ReqID 值和 ReqCount 各为 1。但是,我想展示 R03 的 3 门课程中的 2 门的灵活性,并且对称性表明 ReqID R02 与 ReqCount 3 在某些方面更好。

选择有资格毕业的学生

哪些学生有资格毕业?

假设一个包含 StudentID、Name 和 MajorID 列(以及其他列,例如出生日期、入学日期等)的学生表,以及另一个包含 StudentID 和 CourseID 列的 StudentPassedCourses(以及通过日期和通过成绩等)。条目仅在学生通过课程后出现在 StudentPassedCourses 中。

那么有资格毕业的学生就是那些满足了他们专业的每一项要求的学生。

让我们使用TDQD(测试驱动查询设计)逐步构建查询。

Q1:专业毕业要求数量

SELECT MajorID, COUNT(ReqID) AS CountReqs
  FROM MajorRequirements
 GROUP BY MajorID

Q2:学生要求的通过次数

SELECT s.StudentID, m.ReqID, COUNT(*) AS PassCount
  FROM StudentPassedCourses AS p
  JOIN Students             AS s ON p.StudentID = s.StudentID
  JOIN MajorRequirements    AS m ON s.MajorID = m.MajorID
 GROUP BY s.StudentID, m.ReqID

(这是一个相当大的步骤;它可能需要分解为单独的步骤。)

Q3:满足特定要求的学生

这列出了学生和要求 ID,其中给定 ReqID 的学生通过计数至少是专业要求的通过计数。

SELECT p.StudentID, p.ReqID
  FROM (SELECT s.StudentID, m.ReqID, COUNT(*) AS PassCount  -- Q2
          FROM StudentPassedCourses AS p
          JOIN Students             AS s ON p.StudentID = s.StudentID
          JOIN MajorRequirements    AS m ON s.MajorID = m.MajorID
         GROUP BY s.StudentID, m.ReqID
       ) AS p
  JOIN MajorRequirements AS m ON p.ReqID = m.ReqID
 WHERE p.PassCount >= m.ReqCount

Q4:每个学生的总要求数

SELECT r.StudentID, COUNT(*) AS ReqsPassed
  FROM (SELECT p.StudentID, p.ReqID  -- Q3
          FROM (SELECT s.StudentID, m.ReqID, COUNT(*) AS PassCount  -- Q2
                  FROM StudentPassedCourses AS p
                  JOIN Students             AS s ON p.StudentID = s.StudentID
                  JOIN MajorRequirements    AS m ON s.MajorID = m.MajorID
                 GROUP BY s.StudentID, m.ReqID
               ) AS p
          JOIN MajorRequirements AS m ON p.ReqID = m.ReqID
         WHERE p.PassCount >= m.ReqCount
       ) AS r
 GROUP BY r.StudentID

Q5:专业通过的学生

SELECT s.StudentID, s.Name, s.MajorID, m.Name Major
  FROM Students AS s
  JOIN Majors   AS m ON m.MajorID = s.MajorID
  JOIN (SELECT r.StudentID, COUNT(*) AS ReqsPassed  -- Q4
          FROM (SELECT p.StudentID, p.ReqID  -- Q3
                  FROM (SELECT s.StudentID, m.ReqID, COUNT(*) AS PassCount  -- Q2
                          FROM StudentPassedCourses AS p
                          JOIN Students             AS s ON p.StudentID = s.StudentID
                          JOIN MajorRequirements    AS m ON s.MajorID = m.MajorID
                         GROUP BY s.StudentID, m.ReqID
                       ) AS p
                  JOIN MajorRequirements AS m ON p.ReqID = m.ReqID
                 WHERE p.PassCount >= m.ReqCount
               ) AS r
         GROUP BY r.StudentID
       )        AS c ON c.StudentID = s.StudentID
  JOIN (SELECT MajorID, COUNT(ReqID) AS CountReqs    -- Q1
          FROM MajorRequirements
         GROUP BY MajorID
       )        AS r ON r.MajorID = s.MajorID
 WHERE c.ReqsPassed >= r.CountReqs

警告:未经测试的 SQL!

于 2013-03-15T23:23:59.563 回答
2

一个专业有要求,一个要求可以通过课程来填补。这样,专业也可以分享共同的要求。

major  requirementId
-----------------------
econ       1
econ       2
artOrSmth  2


requirementId     coursename
------------------------------
    1              econ101
    1              econ102
    2              math101
于 2013-03-15T15:39:32.950 回答