Concepts / One-to-Many Relationships: Linking Tables with Foreign Keys

One-to-Many Relationships: Linking Tables with Foreign Keys

A junction table is an intermediate table that resolves many-to-many relationships by breaking them into two one-to-many relationships.

  • Programming

The Relationship Problem

Suppose students enroll in courses. One student can take many courses, and one course can have many students. This is a many-to-many relationship: both sides can be connected to multiple records on the other side.

A direct design creates a storage problem. A single database cell cannot hold a list of values, so adding one course_id column to a User table would not be enough to store every course taken by one student. The same problem appears if you try to store every student directly in one Course-table cell.

many-to-manyone-to-manymany-to-oneStudentStudentCourseMemberuser_id, course_idCourse
What changes when one direct many-to-many relationship is replaced by two one-to-many relationships through an intermediate table?

The Junction Table

A junction table is an intermediate table that resolves a many-to-many relationship by breaking it into two one-to-many relationships.

For the student-and-course relationship, the junction table is called Member. Each Member row represents one enrollment: it links one specific user_id to one specific course_id. The table does not represent a student by itself or a course by itself. It represents the association between them.

user_idcourse_ideach row representsUserprimary keyMemberuser_id, course_idOne enrollmentone user_id + one course_idCourseprimary key
What does the junction table contain, and how do its rows represent associations between the two entity tables?

The minimum useful structure of this junction table is two columns: one foreign key for each related table. In this example, user_id references the User table's primary key, and course_id references the Course table's primary key.

Foreign-Key Connections

A foreign key in the junction table points to a related table. The user_id column points toward the User table, while the course_id column points toward the Course table. Together, these columns let each Member row connect one record from each parent table.

referencesreferencesUser primary keyuser_idforeign keycourse_idforeign keyCourse primary key
Which columns point to the related tables, and how do those foreign keys establish each association?

Composite Uniqueness

A junction table typically uses a composite primary key made from its two foreign-key columns. In the Member table, the pair user_id and course_id identifies a relationship. Using the pair together helps ensure that the same student-course association is not represented more than once.

part ofpart ofidentifiesuser_idone studentuser_id + course_idcomposite primary keyEnrollmentunique associationcourse_idone course
How do the two foreign-key columns together identify one relationship and prevent duplicate associations?
Junction-table elementPurpose
user_idForeign key pointing to the User table
course_idForeign key pointing to the Course table
user_id + course_idComposite primary key representing the relationship

The two foreign keys connect the tables; together they identify the association.

Following the Data Path

Finding a Student's Courses

How can the database find all courses taken by one particular student?

Start with the User record: Identify the user whose courses are needed.

Search Member: Look in the Member table for every row whose user_id matches that user.

Collect course_id values: Each matching Member row supplies a course_id.

Retrieve Course records: Use those course_id values to find the corresponding records in the Course table.

The junction table acts as the bridge from one User record to the related Course records.

match user_idread course_idfind matching coursesUser recordchosen studentMember rowsmatching user_id valuescourse_id valuesmatching course identifiersCourse recordsenrolled courses
How does a record in one table connect through the junction table to records in the other table?

The reverse lookup follows the same bridge in the opposite direction. To find all students enrolled in one course, match the course_id in Member, collect the user_id values from those rows, and use those values to retrieve the related User records.

Common Design Mistakes

  • Putting every course identifier into one User-table cell

    A single database cell can hold one value, not a list of values.

    Fix: Use one Member row for each student-course enrollment.

  • Putting every student directly into one Course-table cell

    The many students connected to one course cannot be represented as one value in one cell.

    Fix: Store each association in the junction table with a user_id and a course_id.

  • Treating the junction table as optional for a many-to-many relationship

    The direct design does not provide a row-based way to represent each individual association.

    Fix: Resolve the many-to-many relationship into two one-to-many relationships through a junction table.

  • Using only one side of the relationship in the junction table

    The junction row must identify a record from both related tables.

    Fix: Include one foreign key for each related table.

Practice the Trace

EASY

A student is connected to several rows in Member. Describe the steps needed to find that student's courses, and identify which column is used at each step.

Hints
  • Begin with the matching user_id in Member.
  • Read the course_id values from the matching rows.
  • Use those course_id values to retrieve records from Course.
MEDIUM

Explain why user_id and course_id are better understood as a pair in the junction table rather than as two unrelated columns.

Hints
  • Each Member row represents one enrollment.
  • The two foreign-key values identify the two records participating in that enrollment.
  • The pair can serve as a composite primary key for relationship uniqueness.

Design Checklist

  1. Recognize that both entity tables can have many related records.
  2. Create an intermediate junction table to resolve the many-to-many relationship.
  3. Add one foreign key for each related table.
  4. Represent each individual association as one junction-table row.
  5. Use the two foreign-key columns together as a composite primary key when the relationship must be unique.
  6. Trace queries through the junction table: match one foreign key, read the other, and retrieve the related parent records.

Key Takeaways

  • A many-to-many relationship cannot be represented by placing a list of values in one database cell.
  • A junction table resolves the relationship into two one-to-many relationships.
  • The junction table contains a foreign key for each related table.
  • Each junction-table row represents one association between two records.
  • A composite primary key made from the two foreign keys helps ensure that the same relationship is not duplicated.