我有三个简单的实体:
课程就像一本书,是一种可销售的产品。课程实体代表课程,并具有各种属性,例如持续时间,费用,作者,类型等。
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列来解决上述问题。然后在表格上应用检查约束以确保:
这将确保CourseContentId不会同时出现在两个表中。
答案 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);
这种方法给我带来的好处是:
注意:检查约束在MySQL中不起作用。为此,需要使用触发器。