引用多个表中的数据

Referencing data from multiple tables

我有三个简单的实体:

课程就像一本书,一种畅销产品。 Course 实体表示一门课程并具有各种属性,例如 Duration、Fees、Author、Type 等。

Course 
{
    int Id;
    string Title;
}

主题就像书中的一页,它有实际的学习内容。一个主题可能出现在多门课程中。

Topic
{
    int Id;
    string Title;
}

在一本书的上下文中,测验也是一个单独的页面,其中包含问题而不是学习内容。同样,一个测验可能会出现在多个课程中。

Quiz
{
    int Id;
    string Title;
}

现在我有了单独的主题和测验,我希望有一个 table 可以将 assemble 主题和测验写成一本书。将此 table 视为书中目录的 Table。下面是我期望它看起来像的轮廓:

CourseContents
{
     int CourseId; // Foreign-Key to Courses.Id
     int Page;     // Foreign-Key to either Topic.Id or Quiz.Id
     int SNo;      // Sequence of this page (topic/quiz) in the course, much like page number in a book.
     int Type      // Type of the page i.e, Quiz or Topic. 
}

有什么方法可以在 RDBMS 中实现这一点吗?

尝试解决

我正在研究的一种方法是创建 table 来为给定的课程项目创建唯一标识符。然后将其用于映射 tables 课程主题和课程测验。请参考以下:

CourseContents
{
    int Id;        // CourseContentId Primary-Key for this table
    int CourseId;  // Foreign key to Course.Id
    int SNo;       // Serial number of an item in this course;
}

CourseTopics
{
    int TopicId;             // Foreign-Key to Topics.Id
    int CourseContentsId;    // Foreign-Key to CourseContents.Id
}

CourseQuizzes
{
    int QuizId;               // Foreign-Key to Quizzes.Id
    int CourseContentsId;     // Serial number of the quiz in the course
}

问题: CourseContentId 表示特定课程中的特定位置(Topic/Quiz)。两个项目不能在课程序列中占据相同的位置,因此一个 CourseContentId 必须仅与 CourseTopics 或 CourseQuizzes 中的一个项目相关联。我们如何在两个 table 之间对 CourseContentsId 设置唯一约束?

进一步添加

上述问题可以通过在CourseContents、CourseTopics 和CourseQuizzes 列中添加ContentType 列来解决。然后在 table 上应用 检查约束 以确保:

这将确保 CourseContentId 不会同时出现在 table 中。

The CourseContentId represent a particular position ( of Topic/Quiz ) in a particular course.

CourseTopics
{
    int TopicId;             // Foreign-Key to Topics.Id

    int CourseContentsId;  -- first of 3-part FK
    int Page;              -- added
    int SNo;               -- added
    PRIMARY KEY(TopicId, CourseContentsId, Page, SNo), -- for JOINing one way
    INDEX      (CourseContentsId, Page, SNo, TopicId)  -- for JOINing the otehr way
}

与此同时,...

猜测你的主要问题体现在这一行:

int Page; // Foreign-Key to either Topic.Id or Quiz.Id

那是不切实际的。解决方案是为 TopicPage 设置一个 single table 并从那里区分。

CREATE TABLE CourseContents (
  CourseContentsId INTEGER NOT NULL PRIMARY KEY,
  CourseContentType CHAR(1) CHECK (CourseContentType IN ('T', 'Q')),
  CourseId INTEGER REFERENCES Courses(Id),
  SNo INTEGER NOT NULL,
  CONSTRAINT UniqueCourseContent UNIQUE (CourseId, SNo),
  CONSTRAINT UniqueCourseContentMapping UNIQUE (CourseContentsId, CourseContentType),
);

课程内容 table 为每个 CourseId 和 SNo 组合生成一个唯一 ID ( CourseContentsId ),然后可以在主题和测验 table 中引用它。由于有两个不同的 tables(主题和测验),我们引入了另一个列来标识它所链接到的内容 (Topic/Quiz) 的类型。通过对 CourseContentsId 和 CourseContentType 使用复合 UNIQUE 约束,我们确保每个条目只能链接到一种内容类型。

CREATE TABLE CourseTopics (
  CourseContentsId INTEGER NOT NULL,
  CourseContentType CHAR(1) DEFAULT 'T' CHECK (CourseContentType = 'T'),
  TopicId INTEGER REFERENCES Topics(Id),
  PRIMARY KEY (CourseContentsId, CourseContentType),
  FOREIGN KEY (CourseContentsId, CourseContentType) REFERENCES CourseContents (CourseContentsId, CourseContentType)
);

课程主题 table 是主题和课程之间的映射 table(我们在课程和主题 table 之间存在多对多关系)。 CourseContents table 的外键和主键确保每个 CourseContent 都有一个条目(换句话说就是 Course 和 SNo)。 table 将 CourseContentType 限制为仅接受 'T',这意味着给定的 CourseContentId 必须具有主题的内容类型才能与主题链接。

CREATE TABLE CourseQuizzes (
  CourseContentsId INTEGER NOT NULL,
  CourseContentType CHAR(1) DEFAULT 'Q' CHECK (CourseContentType = 'Q'),
  QuizId INTEGER REFERENCES Quizzes(Id),
  PRIMARY KEY (CourseContentsId, CourseContentType),
  FOREIGN KEY (CourseContentsId, CourseContentType) REFERENCES CourseContents (CourseContentsId, CourseContentType)
);

与主题 table 类似,我们现在创建课程测验 table。唯一不同的是这里我们有 CourseContentType 'Q'.

最后,为了简化查询,我们可以创建一个将这些 table 连接在一起的视图。例如,下面的视图将列出:CourseId、SNo、ContentType、TopicId、QuizId。在一本书的上下文中,通过此视图,您可以获得给定书籍(课程)的特定页码 (SNo) 上的内容,以及页面上的内容类型(主题或测验)和内容的 ID。

CREATE VIEW CourseContents_All AS 
SELECT CourseContents.CourseId, CourseContents.SNo, CourseContents.CourseContentType , CourseTopics.Id, CourseQuizzes.Id
FROM CourseContents
LEFT JOIN CourseTopics ON (CourseContents.CourseContentsId = CourseTopics.CourseContentsId)
LEFT JOIN CourseQuizzes ON (CourseContents.CourseContentsId = CourseQuizzes.CourseContentsId);

我觉得这种方法的优点是:

  1. 此结构遵循继承,这意味着我们可以通过添加另一个 table 并修改 CourseContents table.
  2. 中的 CourseContentType 检查约束来支持更多内容类型
  3. 对于给定的 CourseId 和 SNo。我也知道内容类型。这肯定会对应用程序代码有所帮助。

Note : Check constraint does not work in MySQL. For it one needs to use Triggers instead.