引用来自多个表的数据

时间:2018-11-27 14:59:53

标签: mysql database postgresql database-design rdbms

我有三个简单的实体:

课程就像一本书,是一种可销售的产品。课程实体代表课程,并具有各种属性,例如持续时间,费用,作者,类型等。

Course 
{
    int Id;
    string Title;
}

主题就像一本书中的单个页面,具有实际的学习内容。一个主题可能会出现在多个课程中。

Topic
{
    int Id;
    string Title;
}

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

Quiz
{
    int Id;
    string Title;
}

现在我有个人的主题和测验,我希望有一个表格将主题和测验组装成一本书。将此表视为书中的目录。以下是我希望它看起来像的轮廓:

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中有什么方法可以实现这一目标吗?

尝试解决方案

我正在寻找的一种方法是创建一个表,以为给定的课程项目创建唯一的标识符。然后在映射表“课程-主题”和“课程-测验”中使用它。请参考以下内容:

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中的一个项目相关联。我们如何在两个表之间对CourseContentsId施加唯一约束?

进一步添加

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

  • CourseContents具有CourseContentId和ContentType的唯一组合。
  • 课程主题和课程测验必须具有相同的内容类型。
  • 在CourseTopics和CourseQuizzes表中添加引用CourseContents(CourseContentId,ContentType)的外键。

这将确保CourseContentId不会同时出现在两个表中。

2 个答案:

答案 0 :(得分:0)

  

CourseContentId代表特定课程中(主题/测验)的特定位置。

CREATE TYPE

同时,...

猜测,您的主要问题体现在这一行中:

  

int页面; //指向Topic.Id或Quiz.Id的外键

那是不切实际的。解决方案是为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 } Topic创建一个单个表,并从中进行区分。

答案 1 :(得分:0)

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),
);

课程内容表会为每个CourseId和SNo组合生成一个唯一ID(CourseContentsId),然后可以在Topics&Quizzes表中进行引用。由于有两个不同的表(主题和测验),因此我们引入了另一列,用于标识链接到的内容的类型(主题/测验)。通过对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)
);

课程主题表是“主题”和“课程”之间的映射表(“课程和主题”表之间存在多对多关系)。 CourseContents表的外键和主键可确保我们为每个CourseContent输入一个条目(即Course&SNo)。该表将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)
);

类似于主题表,我们现在创建CourseQuizzes表。唯一的区别是,这里有CourseContentType'Q'。

最后,为了简化查询,我们可以创建一个将这些表连接在一起的视图。例如,下面的视图将列出: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. 此结构遵循继承性,这意味着我们只需添加另一个表并修改CourseContents表中的CourseContentType Check约束即可支持更多内容类型。
  2. 对于给定的CourseId和SNo。我也知道内容类型。这肯定会对应用程序代码有所帮助。
  

注意:检查约束在MySQL中不起作用。为此,需要使用触发器。