5

I'm putting together a database structure that can hold data for courses. Each course - will have several chapters and each chapter MAY have topics and each topic MAY have sub topics and so on.

This is sample data

Course - Accounts
1) Introduction to Accounts
   a) Basic Accounts
2) Financial Statements
   a) Income statement
      i) Depreciation
   b) Cash Flow Statement
3) Career as an accountant 

Now each of these topics will have lecture notes associated with them. Now the way I'm thinking is incase of Chapter 1 - "Introduction" - the notes are going to be associated with the topic "Basic Accounts". But in chapter 2 - "Income Statement" wont have any notes but "Depreciation" is going to have notes. Now since Chapter 3 "Career as Accountant" does not have any sub topics - the notes are going to be associated directly with it.

This is just my way or organizing - I can enforce rules saying each chapter must have a subtopic so notes can be associated etc.

This is what I have so far

Table: Course
course_id
course_name

Table: Topics
topic_id
parent_topic_id
topic_name
notes

Table: Course_Topics
course_id
topic_id

So the sample data would appear as

Course_id  |  Course Name
    1          Accounts

Topic_id  | Parent_topic_id  |   topic_name           | notes
    1             0             Introduction
    2             1             Basic Accounts
    3             0             Financial Statements
    4             3             Income Statements
    5             4             Depreciation

Course_id   |    Topic_id
    1               1
    1               2
    1               3
    1               4
    1               5

Here is what I'm looking for: 1) Is there a better way to design this - should I enforce stricter rules on how notes are associated with chapters or topics or sub topics

2) Secondly - given this data structure - if I wanted to pull all topics for a given course and display them in the chapter -> topic -> sub topic tree structure format. How would I do that. Should I just pull out all topics based on the course id and then in server side store them in data structures and organize them according to chapter/topic/subtopic wise or is there a cleaner way of doing it using sub queries.

Sorry for the long post - just wanted to clearly explain. Thanks for your time

****** EDIT ********

Thanks for all the answers guy. I came across this other approach of adding a lineage column and a deep column to the table.

The approach is explained here as "Flat table model done right" http://www.ferdychristant.com/blog/archive/DOMM-7QJPM7

What do you guys think of this approach.

Secondly - John raised a good point in his answer. How would I handle inserts in between.
- Chapters (parent_id =0) Say if I want to insert a new chapter between chapter 1 and 2
- Topic (parent_id != 0 ) If I want to insert a new topic between any two existing topics

Should I have another column that maintains the order like 1,2,3 and then if I want to insert something in between chapters 1 and 2 - insert it with a value 1.1 or something like that - can the same column be used for topics as well.

Thanks again

Gublooo
  • 2,550
  • 8
  • 54
  • 91

4 Answers4

5

Skip the table course_topics if it's a one-to-many relationship.

You can make it

Table: Course
course_id
course_name

Table: Topics
topic_id
parent_topic_id
topic_name
notes
course_id

Notes seems fine if it's just one text field. If there are more you'll need to branch it out to another table.

Your 2nd question is very interesting... It can be done using a recursive join. ie you can use a CTE(Common table expression) to recursively join the table to itself. While displaying it just use a level field denoting which level in the hierarchy it is in and order it something like

order level
000   0
000.1 1
000.2 2
001.1 0
001.2 1

Just search for hierarchical data in sql... Since u use mysql and if you think u want to go for adjacency list or nested list here's an analysis. http://explainextended.com/2009/09/29/adjacency-list-vs-nested-sets-mysql/ and also.... look at this question it explains a lot -> What are the options for storing hierarchical data in a relational database?

Community
  • 1
  • 1
Whimsical
  • 5,985
  • 1
  • 31
  • 39
  • Yes that makes sense - course_topics is not required. Also thanks for the tip on 2nd question - I always struggle with these recursive queries and end up doing the ordering on the server side. – Gublooo Aug 31 '11 at 19:12
  • its very simple query. but u need to remember its gonna have a lot of self joins...so a small dataset like 100000 rows can hit 1 sec for entire table performance in normal db boxes. performance is gonna be ur concern. Also remember that server side is not gonna help improve performance. – Whimsical Aug 31 '11 at 19:18
  • @Mulki - I edited the question with some new information - wanted to see your thoughts on it – Gublooo Sep 01 '11 at 17:53
  • @Gublooo - while it will work...im against storing redundant data in the name of speed increase. Any change on the lineage which is inconsistent with the hierarchy could be a nightmare to detect – Whimsical Sep 06 '11 at 07:56
2

Depending on your RDBMS (Relational Database Management Server), there may be a hierarchy_id data type, which is made for this exact kind of scenario.

The design that you're using is known as the "linked list" model or "adjacency list" model. There are definitely some big drawbacks to it, such as the requirement to use recursion for a lot of queries.

Another option is to use the "nested sets" model. A Google search for "joe celko nested sets" should yield some articles on the subject. You can also read his book on the entire subject of modeling trees and hierarchies in relational data models. This method also has some drawbacks (updates, inserts, and deletes can be more complex).

I would check out all three models and decide which fits best for your situation.

Tom H
  • 46,766
  • 14
  • 87
  • 128
  • I forgot to mention that - I'm using Mysql. Thats good information you've provided - I will read about these - Thanks a lot – Gublooo Aug 31 '11 at 19:09
0

You can do all of this with just one table for Chapters and Topics. You need 2 fields, order which simply keeps track of the ordering of the items and level which is how many levels of indentation you need.

The benefit of this approach is that it removes the need for an arbitrary number of tables to capture chapter, topic, sub-topic, sub-sub-topic, etc.

The downside is you don't have any reference data around which topics belong to which other topics. But that information is computable. Also, you need to manage the order field whenever you modify a row.

hvgotcodes
  • 118,147
  • 33
  • 203
  • 236
  • This also requires the updating of multiple rows to keep the `order` in sync when inserting, deleting, etc. That might be ok, but it's something to keep in mind. – Tom H Aug 31 '11 at 19:01
  • But this approach would be very painful to maintain right. Like you and Tom pointed out keeping the order in sync would be a challenge. I will give it a thought - thanks a lot – Gublooo Aug 31 '11 at 19:23
0

It's not a bad first cut.

I'd add a section_designator field to your Topics table. If it's a chapter, you can call it "Chapter 3". If you have a section in that chapter, you can call it "Section 4" in that topic, and then concatenate the section_designators from that and all of its parents to get the full hierarchy ("Chapter 3 Section 4").

Nothing wrong with organizing the data server side as you've described.

John
  • 15,990
  • 10
  • 70
  • 110
  • depending on the hierarchy this information can be infered. no need to mark it explicitly. eg: If it comes at level 0 its a chapter,level 1 its a topic and level 2 its a subtopic. – Whimsical Aug 31 '11 at 19:05
  • Thats a pretty neat suggestion. Even in the correct structure - using the parent_topic_id - I should be able to deduce if its a chapter (parent_id=0) or a section. And then if there are multiple sections, then depending on the order of topic_id deduce if its section 1 or 2 - yeah it'll get messy - Thanks for the tip – Gublooo Aug 31 '11 at 19:19
  • @Mulki - sorry I missed ur comment - I typed in the same thing – Gublooo Aug 31 '11 at 19:20
  • 1
    Right - you can get away with not including "Chapter" in the database but you'll still want some kind of mechanism to denote ordering of chapters, sections within a chapter, etc. You can shoehorn it in based on the record id's in the table, but then you're stuck. What if you want to insert a section in the middle of your course later? As it is now if you're intending to use autoincrement for the indices, you'll have to re-insert all of the topics for a particular course in the correct order. – John Aug 31 '11 at 20:28
  • @John - thanks for pointing that out. It didn't occur to me. So even if I add a section_designator column like you mentioned - and if I want to enter a new section say between current section 1 and section 2 - I would have to go and update all the section_designator columns from section 2 onwards right – Gublooo Sep 01 '11 at 08:19