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 LessonNoSectionLesson.SectionLesson identifies the lesson within the section, such that it has meaning within the course and section, independent of the LessonNoCourse 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 CourseCourseLesson.AK prevents the Lesson from being duplicated within the simple CourseSectionLesson.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