Monday, October 12, 2026

Case Study: How Foreign Keys are Useful in SQL

Consider a growing training company that offers courses to individual learners and to employees of business clients. It stores information about learners, courses, and course registrations in a relational database.

At first, the company keeps these records in a single spreadsheet. Each row contains a learner’s name and email, the course title, the instructor, the registration date, and the learner’s status. This works while the company has a small number of registrations. As the business expands, however, the spreadsheet becomes difficult to manage.

The same learner’s contact information is copied into many rows. If that learner changes their email address, staff must find and correct every occurrence. Course titles and instructor details are repeated, too. Mistakes are inevitable: a course may be entered with slightly different names, or a registration may refer to a learner who does not exist in the learner list. These problems are examples of inconsistent and unreliable data.

The company decides to move its information into a SQL database and separate the records into related tables. Foreign keys help connect those tables while ensuring that their relationships remain valid.

## Designing the tables

The database uses three main tables:

- `Learners` stores one record for each learner. - `Courses` stores one record for each course. - `Registrations` records which learner has registered for which course.

A simplified schema might look like this:

```sql CREATE TABLE Learners ( learner_id INT PRIMARY KEY, full_name VARCHAR(100) NOT NULL, email VARCHAR(255) NOT NULL UNIQUE );

CREATE TABLE Courses ( course_id INT PRIMARY KEY, course_title VARCHAR(150) NOT NULL );

CREATE TABLE Registrations ( registration_id INT PRIMARY KEY, learner_id INT NOT NULL, course_id INT NOT NULL, registration_date DATE NOT NULL, status VARCHAR(20) NOT NULL,

FOREIGN KEY (learner_id) REFERENCES Learners(learner_id),

FOREIGN KEY (course_id) REFERENCES Courses(course_id) ); ```

The `learner_id` and `course_id` columns are primary keys in their respective tables. Each primary key identifies one row uniquely. In `Registrations`, the same columns are foreign keys: they refer to primary keys in `Learners` and `Courses`.

A registration can therefore connect a learner to a course without copying the learner’s name, email address, or course title into every registration row. The database stores each person and course once, then uses identifiers to link them to registrations.

## Preventing invalid registrations

The most immediate benefit of the foreign keys is that they prevent registrations from referring to records that do not exist.

Suppose an employee attempts to add this registration:

```sql INSERT INTO Registrations ( registration_id, learner_id, course_id, registration_date, status ) VALUES (501, 9999, 12, '2025-04-10', 'confirmed'); ```

If there is no learner with `learner_id` 9999, the database rejects the insert. The `learner_id` foreign key requires the value in `Registrations` to match an existing value in `Learners`. The same rule applies to `course_id`: a registration cannot refer to a course that is absent from the `Courses` table.

Without this rule, the database could accept an entry that appears to represent a registration but cannot be connected to a real learner. Such a row is often called an orphan record. It may cause problems in reports, billing, attendance lists, and customer support. A report that joins registrations to learners, for example, might omit the orphan record because there is no matching learner row.

Foreign keys make this a database-level rule rather than a reminder for staff or an assumption built into application code. Any application, script, or person that writes to the database must follow the same constraint.

## Keeping information consistent

Separating learners and registrations also reduces repeated information. A learner’s email is stored in one place rather than copied into every course registration. When the learner changes their email, the company updates the learner row once:

```sql UPDATE Learners SET email = 'alex.morgan@example.com' WHERE learner_id = 104; ```

Registrations continue to point to learner 104, so they remain associated with that person. The database does not need to update every registration row because those rows store the stable identifier, not a copy of the email address.

This design helps avoid update anomalies. If the email were copied into ten registration rows, changing only nine of them would leave conflicting information. A foreign key does not itself prevent every possible data-quality issue, but it supports a structure in which related facts are stored in appropriate places and connected reliably.

The company can retrieve a registration together with its related details using a join:

```sql SELECT l.full_name, l.email, c.course_title, r.registration_date, r.status FROM Registrations AS r JOIN Learners AS l ON r.learner_id = l.learner_id JOIN Courses AS c ON r.course_id = c.course_id; ```

The foreign keys establish the relationships that these joins use. They also help make the schema easier for developers and database users to understand: `Registrations.learner_id` points to a learner, and `Registrations.course_id` points to a course.

## Controlling deletions

Foreign keys are also useful when records are deleted. Suppose the company tries to delete a learner who still has registrations. With the default restrictive behavior in many database systems, the database refuses the deletion. This prevents the company from removing the person’s main record while leaving registrations that refer to it.

That behavior may be appropriate when registrations must be preserved for financial or historical records. Staff can first decide what should happen to the registrations, rather than accidentally creating broken references.

SQL also allows a database designer to specify what happens when a referenced row is deleted. For example, `ON DELETE CASCADE` automatically deletes dependent rows:

```sql FOREIGN KEY (learner_id) REFERENCES Learners(learner_id) ON DELETE CASCADE ```

If the learner is deleted, their registrations are deleted as well. This may suit temporary data or a system where dependent records have no independent value. It can be dangerous in a training company, however. Deleting one learner might remove years of registration history. The choice should reflect business rules, not just convenience.

Another option is `ON DELETE SET NULL`, which sets the foreign-key column to `NULL` when the referenced row is deleted. This requires the column to allow `NULL`, and it may not make sense when every registration must have a learner. Some databases also support additional referential actions. Their exact behavior and syntax can vary, so the team should confirm the rules for its database system.

The company might choose to keep historical registrations but mark a learner as inactive instead of deleting the learner record. That approach preserves the relationship and history while preventing new registrations. A foreign key does not decide the organization’s retention policy; it ensures that whatever policy is chosen does not silently leave invalid links.

## Preventing duplicate registrations

The first schema guarantees that every registration refers to a valid learner and course, but it still allows the same learner to register for the same course multiple times. Whether that is valid depends on the company’s rules. If learners may register only once per course, a composite uniqueness constraint can enforce that:

```sql ALTER TABLE Registrations ADD CONSTRAINT unique_learner_course UNIQUE (learner_id, course_id); ```

This constraint is not itself a foreign key, but it complements the foreign keys. The foreign keys ensure that both referenced records exist; the unique constraint ensures that the pair does not appear more than once.

If learners are allowed to retake courses, the design may need a different rule, such as including a course session or attempt number in the unique key. This illustrates an important point: foreign keys protect relationships, while other constraints protect other aspects of the data. A reliable schema usually combines primary keys, foreign keys, `NOT NULL`, `UNIQUE`, and appropriate validation rules.

## Supporting reports and daily operations

With valid relationships in place, the company can rely on its reports more confidently. For instance, it can count registrations by course:

```sql SELECT c.course_title, COUNT(r.registration_id) AS registration_count FROM Courses AS c LEFT JOIN Registrations AS r ON r.course_id = c.course_id GROUP BY c.course_id, c.course_title; ```

Because the foreign key prevents registrations from pointing to nonexistent courses, the company is less likely to encounter unexplained registration rows that cannot be assigned to a course. The `LEFT JOIN` also includes courses with no registrations, which can help staff identify offerings that have not attracted learners.

Foreign keys can support operational workflows as well. A staff member can add a new course before accepting registrations, then add registrations that refer to it. If the course has not yet been entered, the database rejects the registration. This signals that the process is incomplete and directs staff to correct the missing record.

The constraint is useful even when the company has a web application that checks whether a learner and course exist before submitting a registration. Application checks can improve the user experience by displaying a helpful message. But they are not a substitute for database constraints: another application, an import process, or a direct SQL command might bypass them. The foreign key provides a final safeguard at the point where the data is stored.

## Practical considerations and limitations

Foreign keys need to be designed with care. The columns on both sides must have compatible data types, and the referenced column must normally be a primary key or otherwise uniquely constrained. The names and exact requirements depend on the SQL database system.

The team should also consider performance. A foreign key check involves verifying that a referenced row exists, and deletes or updates may require checking dependent rows. Indexing foreign-key columns can help queries and certain database operations, especially when tables grow large. Some database systems create indexes automatically in particular circumstances, while others do not, so the behavior should be checked rather than assumed.

Foreign keys do not guarantee that all information is accurate. They cannot determine whether a person typed the correct email address, whether a course description is current, or whether the learner is eligible for a particular course. Those concerns require additional validation, business rules, or review processes. A valid reference means that the referenced row exists—not necessarily that the overall business decision is correct.

The company must also account for differences among database products. Referential actions, constraint enforcement settings, and migration procedures can vary. For example, some systems allow foreign-key enforcement to be configured, and bulk imports may require special planning. The database team should test the intended behavior in the system it actually uses.

## The result

After adopting the relational design, the training company has a clearer and more dependable record of its operations. Learners and courses are stored once, registrations refer to them through identifiers, and the database blocks references to nonexistent records. Updates are easier because contact details are not duplicated across registrations. Deletions follow deliberate rules, and reports can connect related information through reliable joins.

The central value of a foreign key is simple: it turns a relationship that might otherwise exist only in people’s assumptions or application code into a rule the database can enforce. In this case study, that rule prevents invalid registrations, protects historical records, and supports consistent reporting. Used alongside other constraints and thoughtful data policies, foreign keys help organizations keep their SQL data connected, understandable, and trustworthy.

No comments:

Post a Comment