I have three entities:
Each "course" is made up of several "lessons". The "lessons" inside a course, can either be categorized into "sections", or not.
So, the contents of a course could look either like this:
Foo Course:
Lesson 1
Lesson 2
Lesson 3
Lesson 4
Or like this:
Bar Course:
Section 1:
Lesson 1
Lesson 2
Section 2:
Lesson 3
Lesson 4
So, in other words, a course can either directly have "lessons", or it can have "sections" that in turn have "lessons".
From the other perspective, a "lessons" can either directly belong to a "course", or belong to a "section" that in turn belongs to a "course".
I'm struggling to figure out how best to implement a structure like this within a relational database.
If every "lessons" had to necessarily belong to a "section", it would be easy, I could just simply have a "Course" table, a "Section" table with a "CourseId" column, and a "Lesson" table with a "SectionId" column.
But my scenario is not as straightforward as that. A "section" can potentially exist as a middleman between a "course" and several "lessons", but it can also be absent, in which case a "course" directly has the "lessons" and no there are no "sections".
I'd appreciate any suggestions regarding how such a structure can ideally be implemented in the context of relational databases.
Thanks.
a course can either directly have "lessons", or it can have "sections" that in turn have "lessons". a "lessons" can either directly belong to a "course", or belong to a "section" that in turn belongs to a "course".
Lesson
[Safe Use of Hammer] may be inCourse
[Woodwork] as well asCourseSection
[Carpentry, Basics]`Here is an interim model, showing the two types of Courses, and an independent Lesson, awaiting decisions, and further data modelling. Duplicated elements are shown in red.
Forgive me if I don't show the several intermediate steps (not possible in the demanded simple question and answer format). Here is the final data model.
Normalised means no nulls in the database
Nullable Foreign Keys are particularly bad news, strictly forbidden
a "dummy record" is not only awkward and horrible (affects every SELECT
that accesses the table), it is not a Fact, and it is completely unnecessary
RecordIds
are physical; anti-Relational, each requires an additional column and index.
This uses Relational Keys (made up from the data), it provides Relational Integrity (as distinct from Referential Integrity)
CourseLesson.CourseLesson
identifies the lesson within the course, such that it has meaning within the course, independent of the LessonNo
SectionLesson.SectionLesson
identifies the lesson within the section, such that it has meaning within the course and section, independent of the LessonNo
Course
is an Exclusive Subtype, to ensure that:
Course_TypeLesson
has lessons directly, andCourse_TypeSection
has lessons attached to the section, not the course.Lesson
is independent and fully defined (once)
Lesson is used in
either type of Course
CourseLesson.AK
prevents the Lesson
from being duplicated within the simple Course
SectionLesson.AK
prevents the Lesson
from being duplicated within the sectioned Course
.The progressed data model resolves many issues, and hopefully answers your question. But it may expose others, it may need further definition: Data Modelling is an iterative task. Please feel free to comment.
The simplest way to do this is to have two foreign keys on Lesson
:
CourseId null,
SectionId null
Then place a CHECK
constraint on the table
(CourseId IS NOT NULL AND SectionId IS NULL) OR (CourseId IS NULL AND SectionId IS NOT NULL)
This means that either one must be present, but not both. Don't be tempted into placing the CourseId
on a Lesson belonging to a Section, because this introduces a denormalization in the table: if a Section moved to a different Course, then you would need to update all the child Lessons.
Strictly speaking, you should really have a more complex design:
Lesson
CourseLesson
SectionLesson
This makes it impossible to enforce a Lesson being part of only one or the other though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With