Skip to content

Commit 6d8fbd6

Browse files
Merge pull request dimitri-yatsenko#56 from dimitri-yatsenko/claude/add-lookup-tables-discussion-B1O9n
Add lookup tables discussion to Relationships section
2 parents 8600433 + 401933c commit 6d8fbd6

File tree

1 file changed

+30
-0
lines changed

1 file changed

+30
-0
lines changed

book/30-design/050-relationships.ipynb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,36 @@
948948
"dj.Diagram(Student) + dj.Diagram(Course) + dj.Diagram(Enrollment)"
949949
]
950950
},
951+
{
952+
"cell_type": "markdown",
953+
"id": "xa3lj79iple",
954+
"source": "## Enums vs. Lookup Tables for Valid Values\n\nIn the `Enrollment` example above, we used an **enum** to restrict `grade` to valid values: `enum('A', 'B', 'C', 'D', 'F', 'IP')`.\nAn alternative approach uses a **lookup table** to define valid grades.\n\nBoth approaches enforce data integrity, but they have different trade-offs:\n\n`````{tab-set}\n````{tab-item} Using Enum\n:sync: enum\n```python\n@schema\nclass Enrollment(dj.Manual):\n definition = \"\"\"\n -> Student\n -> Course\n ---\n enrollment_date : date\n grade : enum('A', 'B', 'C', 'D', 'F', 'IP')\n \"\"\"\n```\n````\n````{tab-item} Using Lookup Table\n:sync: lookup\n```python\n@schema\nclass LetterGrade(dj.Lookup):\n definition = \"\"\"\n grade : char(2)\n ---\n grade_point = null : decimal(3,2)\n description : varchar(30)\n \"\"\"\n contents = [\n ('A', 4.00, 'Excellent'),\n ('B', 3.00, 'Good'),\n ('C', 2.00, 'Satisfactory'),\n ('D', 1.00, 'Passing'),\n ('F', 0.00, 'Failing'),\n ('IP', None, 'In Progress'),\n ]\n\n@schema\nclass EnrollmentWithLookup(dj.Manual):\n definition = \"\"\"\n -> Student\n -> Course\n ---\n enrollment_date : date\n -> LetterGrade\n \"\"\"\n```\n````\n`````\n\n```{list-table} Enum vs. Lookup Table Comparison\n:header-rows: 1\n:widths: 15 42 43\n\n* - Aspect\n - Enum\n - Lookup Table\n* - **Associated data**\n - Cannot store additional attributes (e.g., grade points)\n - Can include related data like grade points, descriptions\n* - **Modifications**\n - Requires `ALTER TABLE` to add/remove values\n - Add or remove rows without schema changes\n* - **Querying**\n - Values are inline; no join needed\n - Requires join to access the value or related data\n* - **Referential integrity**\n - Enforced by column type\n - Enforced by foreign key constraint\n* - **Complexity**\n - Simple, self-contained\n - Additional table to manage\n* - **Reuse**\n - Must repeat enum definition in each table\n - Single source of truth; multiple tables can reference it\n* - **UI integration**\n - Values must be hardcoded in application\n - Query the table to populate dropdown menus dynamically\n```\n\n```{admonition} When to Use Each Approach\n:class: tip\n\n**Use enums when:**\n- The set of values is small and unlikely to change\n- No additional attributes are associated with each value\n- You want to minimize schema complexity\n\n**Use lookup tables when:**\n- Values need associated attributes (e.g., grade points, descriptions)\n- The set of values may change without requiring schema migration\n- Multiple tables reference the same set of values\n- You need to query or report on the valid values themselves\n- Graphical interfaces or dashboards need to populate dropdown menus—querying a lookup table provides the options dynamically without hardcoding values in the application\n```\n\n```{seealso}\nSee the [Lookup Tables](020-lookup-tables.ipynb) chapter for more details on creating and using lookup tables.\n```",
955+
"metadata": {}
956+
},
957+
{
958+
"cell_type": "code",
959+
"id": "bmty821kwm5",
960+
"source": "# Lookup table approach for grades\n@schema\nclass LetterGrade(dj.Lookup):\n definition = \"\"\"\n grade : char(2)\n ---\n grade_point = null : decimal(3,2)\n description : varchar(30)\n \"\"\"\n contents = [\n ('A', 4.00, 'Excellent'),\n ('B', 3.00, 'Good'),\n ('C', 2.00, 'Satisfactory'),\n ('D', 1.00, 'Passing'),\n ('F', 0.00, 'Failing'),\n ('IP', None, 'In Progress'),\n ]\n\n@schema\nclass EnrollmentWithLookup(dj.Manual):\n definition = \"\"\"\n -> Student\n -> Course\n ---\n enrollment_date : date\n -> LetterGrade\n \"\"\"",
961+
"metadata": {},
962+
"execution_count": null,
963+
"outputs": []
964+
},
965+
{
966+
"cell_type": "code",
967+
"id": "c4ecykge118",
968+
"source": "# View the lookup table contents - notice the associated grade points\nLetterGrade()",
969+
"metadata": {},
970+
"execution_count": null,
971+
"outputs": []
972+
},
973+
{
974+
"cell_type": "code",
975+
"id": "zwvkqwauqip",
976+
"source": "# Compare the diagrams: EnrollmentWithLookup has an additional dependency on LetterGrade\ndj.Diagram(Student) + dj.Diagram(Course) + dj.Diagram(LetterGrade) + dj.Diagram(EnrollmentWithLookup)",
977+
"metadata": {},
978+
"execution_count": null,
979+
"outputs": []
980+
},
951981
{
952982
"cell_type": "markdown",
953983
"id": "cell-21",

0 commit comments

Comments
 (0)