如何在数据库中存储OR关系?

时间:2013-03-15 13:41:59

标签: database

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

课程:CourseID,CourseName

专业:MajorID,MajorName,RequiredCourseID

我如何能够获得有时主要要求的要求:要么选择课程A还是课程B,但不一定都在我的数据库设计中?

2 个答案:

答案 0 :(得分:2)

专业有要求,课程可以填写要求。这种方式专业也可以分享共同的要求。

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


requirementId     coursename
------------------------------
    1              econ101
    1              econ102
    2              math101

答案 1 :(得分:2)

架构设计

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

  • 课程:CourseID,CourseName

  • 专业:MajorID,MajorName

  • MajorRequirements:MajorID,ReqId

  • 要求:ReqId,ReqCount

  • RequiredCourseOptions: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

MajorRequirements

MajorID      ReqID
EC001        R01
EC001        R02
EC002        R01
EC002        R03

要求

ReqID         ReqCount
R01           1
R02           3
R03           2

RequiredCourseOptions

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),学生必须至少选修三门课程。

显然,这可以用于从任何一组中要求任何N个M课程。如果一个专业M需要特定的课程C,那么MajorRequirements表包含一个ReqID R,用于主要M,ReqCount为1,RequiredCourseOptions记录R和C.R02所需的三个课程可以分为三个单独的要求,不同的ReqID值和每个ReqCount为1。但是,我希望通过R03显示3个课程中的2个的灵活性,并且对称性表明ReqID R02与ReqCount 3在某些方面更好。

选择有资格毕业的学生

哪些学生有资格毕业?

假设学生表包含StudentID,Name和MajorID(以及其他列,如出生日期,注册日期等),以及另一个表,StudentPassedCourses,其中包含StudentID和CourseID(以及通过日期和通过等级,等等)。只有学生通过课程后,参赛作品才会出现在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!