SQL Foreign Keys and Relationships — Connecting Tables in Relational Databases

Foreign Keys

An exam result should not claim to belong to a student whose roll number does not exist.

A foreign key restricts child key values to permitted references in a parent relation, subject to the schema’s nullability and configured relationship actions.

  1. Explain and apply

    Connect result rows to valid students and predict what a foreign key rejects.

  2. Work it out

    Identify the deliberately orphaned result in the practice fixture, before designing an enforced relationship.

  3. Avoid mistakes

    Nullable child keys can permit missing relationships unless NOT NULL is required.

Foreign Keys: the request and its result

  1. School need

    An exam result should not claim to belong to a student whose roll number does not exist.

  2. Database operation

    A foreign key restricts child key values to permitted references in a parent relation, subject to the schema’s nullability and configured relationship actions.

  3. Check the outcome

    The sample results relation intentionally has no enforced foreign key so unmatched join behavior can be learned. An appropriate enforced, non-null parent reference would reject that orphan insertion.

A conceptual model. The query examples below show the actual syntax, input data and results.

Understand what the database does

The child stores the parent key. The database checks the relationship when relevant writes occur. ON DELETE and ON UPDATE actions specify whether parent changes are rejected, cascaded or handled in another supported way. A many-to-many relationship uses a junction table with references to both parents.

Related concepts: LEFT JOIN and Data Constraints and Transactions.

What is a Foreign Key?

A foreign key is a column (or set of columns) in one table that refers to the primary key of another table. It establishes a link between two tables and enforces referential integrity — meaning you can't insert unrelated or orphaned data.

Basic School Example

SQL · portable concepts; preserved examples identify their engine

1. Create students table

CREATE TABLE students (
  roll_no INT PRIMARY KEY,
  name VARCHAR(50),
  class VARCHAR(10)
);

2. Create marks table with a foreign key

CREATE TABLE marks (
  id INT AUTO_INCREMENT PRIMARY KEY,
  roll_no INT,
  subject VARCHAR(30),
  marks INT,
  FOREIGN KEY (roll_no) REFERENCES students(roll_no)
);

This means every row in marks must match an existing roll_no in students.

Inserting Valid and Invalid Data

SQL · portable concepts; preserved examples identify their engine

Valid insert:

INSERT INTO students VALUES (1, 'Aarav Sharma', '10A');
INSERT INTO marks (roll_no, subject, marks) VALUES (1, 'Maths', 85);

Invalid insert:

-- Error: roll_no 5 doesn't exist in students table
INSERT INTO marks (roll_no, subject, marks) VALUES (5, 'Science', 90);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails

Types of Relationships Using Foreign Keys

SQL · portable concepts; preserved examples identify their engine

1. One-to-Many (Most Common)

A student can have many marks entries, but each mark entry belongs to one student.

2. Many-to-One

Multiple students can belong to the same class or be assigned to the same teacher.

3. Many-to-Many (via Junction Table)

Students can enroll in many subjects, and subjects can have many students.

CREATE TABLE enrollments (
  roll_no INT,
  subject_code VARCHAR(10),
  PRIMARY KEY (roll_no, subject_code),
  FOREIGN KEY (roll_no) REFERENCES students(roll_no),
  FOREIGN KEY (subject_code) REFERENCES subjects(subject_code)
);

ON DELETE and ON UPDATE Options

SQL · portable concepts; preserved examples identify their engine

Foreign keys can respond to changes in the parent table using:

  • ON DELETE CASCADE: Deletes dependent rows if parent is deleted
  • ON DELETE SET NULL: Sets FK to NULL if parent is deleted
  • ON DELETE RESTRICT: Prevents deletion if child rows exist
CREATE TABLE marks (
  id INT AUTO_INCREMENT PRIMARY KEY,
  roll_no INT,
  subject VARCHAR(30),
  marks INT,
  FOREIGN KEY (roll_no) REFERENCES students(roll_no)
    ON DELETE CASCADE
);

Real-World School Use Cases

  • students → marks: Track subject-wise performance
  • students → attendance: Link attendance records to students
  • subjects → teachers: Assign subjects to teachers
  • students ↔ subjects: Use a join table for student enrollments

Best Practices

Query discussed in this section:

CREATE TABLE marks (
  id INT AUTO_INCREMENT PRIMARY KEY,
  roll_no INT,
  subject VARCHAR(30),
  marks INT,
  FOREIGN KEY (roll_no) REFERENCES students(roll_no)
    ON DELETE CASCADE
);
  • Always index foreign key columns for better performance
  • Name constraints explicitly if needed (for debugging)
  • Use CASCADE only when deletions should flow down
  • Plan your relationships before schema creation (ER diagrams help!)

Important differences and mistakes

Nullable child keys can permit missing relationships unless NOT NULL is required. Cascading deletion has a real scope and should be chosen intentionally. SQLite requires foreign-key enforcement to be enabled per connection in typical setups; MySQL enforcement depends on a supporting engine such as InnoDB.

Try it with the school data

Identify the deliberately orphaned result in the practice fixture, before designing an enforced relationship.

This practice uses a separate, fresh fixture named practice_students. It does not continue the changing table state of the earlier examples.

Practice input: practice_students
roll_nonameclassmarkscity
1Aarav10A85Pune
2Diya9B70Chennai
3Sneha10A85Pune
Practice input: practice_results — includes an orphan intentionally
roll_nosubjectmarks
1Maths85
3Maths85
4Maths92

SQL · create only these practice tables in a disposable database:

CREATE TABLE practice_students (roll_no INTEGER PRIMARY KEY, name VARCHAR(50), class VARCHAR(10), marks INTEGER, city VARCHAR(30));
INSERT INTO practice_students VALUES
(1, 'Aarav', '10A', 85, 'Pune'),
(2, 'Diya', '9B', 70, 'Chennai'),
(3, 'Sneha', '10A', 85, 'Pune');
CREATE TABLE practice_results (roll_no INTEGER, subject VARCHAR(30), marks INTEGER);
INSERT INTO practice_results VALUES (1,'Maths',85),(3,'Maths',85),(4,'Maths',92);

Worked answer and reasoning

This practice uses a separate, fresh fixture named practice_students. It does not continue the changing table state of the earlier examples.

Practice input: practice_students
roll_nonameclassmarkscity
1Aarav10A85Pune
2Diya9B70Chennai
3Sneha10A85Pune
Practice input: practice_results — includes an orphan intentionally
roll_nosubjectmarks
1Maths85
3Maths85
4Maths92

SQL · create only these practice tables in a disposable database:

CREATE TABLE practice_students (roll_no INTEGER PRIMARY KEY, name VARCHAR(50), class VARCHAR(10), marks INTEGER, city VARCHAR(30));
INSERT INTO practice_students VALUES
(1, 'Aarav', '10A', 85, 'Pune'),
(2, 'Diya', '9B', 70, 'Chennai'),
(3, 'Sneha', '10A', 85, 'Pune');
CREATE TABLE practice_results (roll_no INTEGER, subject VARCHAR(30), marks INTEGER);
INSERT INTO practice_results VALUES (1,'Maths',85),(3,'Maths',85),(4,'Maths',92);

SQL · this practice variation runs with SQLite 3; the preserved examples retain their stated dialect

SELECT r.roll_no FROM practice_results AS r LEFT JOIN practice_students AS s ON s.roll_no = r.roll_no WHERE s.roll_no IS NULL ORDER BY r.roll_no;
Expected query result
roll_no
4

The sample results relation intentionally has no enforced foreign key so unmatched join behavior can be learned. An appropriate enforced, non-null parent reference would reject that orphan insertion.

Check your understanding

What does ON DELETE CASCADE request?
Choose one answer. You can try again.

Answer and explanation

Delete matching child rows when the referenced parent row is deleted.

The sample results relation intentionally has no enforced foreign key so unmatched join behavior can be learned. An appropriate enforced, non-null parent reference would reject that orphan insertion.

Use the idea independently

A foreign key restricts child key values to permitted references in a parent relation, subject to the schema’s nullability and configured relationship actions.

The sample results relation intentionally has no enforced foreign key so unmatched join behavior can be learned. An appropriate enforced, non-null parent reference would reject that orphan insertion.

Continue your understanding with LEFT JOIN and Data Constraints and Transactions.

Source for the engine-specific behavior: MySQL 8.4 reference documentation.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: SQL Performance Tuning — Write Faster, Smarter Queries →