Skip to main content
PostgreSQL
CHAPTER 13 Intermediate

Foreign Keys and Table Relationships

Updated: May 16, 2026
7 min read

# CHAPTER 13

Foreign Keys and Table Relationships

1. Introduction

If a database only has one table, it is just an expensive Excel spreadsheet. The true power of PostgreSQL lies in the word "Relational." Data is split into multiple tables to eliminate redundancy, and then mathematically connected. In this chapter, we will learn how to use Foreign Keys to forge unbreakable links between tables, enforcing "Referential Integrity" so that relationships can never be accidentally severed.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Define a Foreign Key constraint.
  • Architect One-to-Many (1:N) relationships.
  • Architect Many-to-Many (N:M) relationships using Pivot tables.
  • Understand Referential Integrity.
  • Use ON DELETE CASCADE to manage child records automatically.

3. The FOREIGN KEY Constraint

A Foreign Key is simply a column in a "Child" table that holds the Primary Key of a "Parent" table. By explicitly defining a Foreign Key constraint, PostgreSQL actively monitors the relationship. If a PHP application tries to insert an order for User #99, but User #99 does not exist in the users table, PostgreSQL will reject the query instantly!

4. One-to-Many Relationships (1:N)

This is the most common relationship in database design.
  • One User can have Many Orders.
  • One Department can have Many Employees.

The Rule: The Foreign Key always goes in the "Many" table (the Child table).

sql
1234567891011121314151617
-- 1. Create the Parent Table First
CREATE TABLE departments (
    dept_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    dept_name VARCHAR(50)
);

-- 2. Create the Child Table
CREATE TABLE employees (
    emp_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    name VARCHAR(50),
    department_id INT, -- This column will hold the Foreign Key
    
    -- The Mathematical Link:
    CONSTRAINT fk_department
        FOREIGN KEY (department_id) 
        REFERENCES departments(dept_id)
);

5. Referential Integrity and ON DELETE CASCADE

What happens if HR completely deletes the "Sales" department (ID: 5) from the parent table, but there are still 100 employees in the child table who have a department_id of 5? Those 100 employees become "Orphans." This is called corrupted data.

By default, PostgreSQL will strictly block you from deleting the Sales department, throwing an error to protect the children. If you want PostgreSQL to automatically delete all the child employees when the parent department is deleted, you use ON DELETE CASCADE.

sql
1234
    CONSTRAINT fk_department
        FOREIGN KEY (department_id) 
        REFERENCES departments(dept_id)
        ON DELETE CASCADE -- If the parent dies, the children die with it.

6. Many-to-Many Relationships (N:M)

A Student can enroll in Many Classes. A Class holds Many Students. You cannot put a classid in the Student table, because they take 5 classes. You cannot put a studentid in the Class table, because it holds 30 students.

The Solution: You must build a 3rd table in the middle, called a "Pivot" (or Junction) table.

sql
123456789
CREATE TABLE students ( id INT PRIMARY KEY, name VARCHAR(50) );
CREATE TABLE classes ( id INT PRIMARY KEY, title VARCHAR(50) );

-- The Pivot Table connecting them together!
CREATE TABLE student_classes (
    student_id INT REFERENCES students(id) ON DELETE CASCADE,
    class_id INT REFERENCES classes(id) ON DELETE CASCADE,
    PRIMARY KEY (student_id, class_id) -- Composite Key!
);

7. One-to-One Relationships (1:1)

One User has exactly One Social Security Number. In 95% of cases, you should just put the SSN as a column in the users table. However, if the SSN data is highly sensitive and you want to isolate it in a separate secure table, you put a Foreign Key in the secure table, and add a UNIQUE constraint to it so it can only link to the User once.

8. Mini Project: E-Commerce Architecture

Let's design the ultimate E-Commerce setup: Users, Orders, and Products.
sql
1234567891011121314151617
CREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(50) );
CREATE TABLE products ( id INT PRIMARY KEY, price NUMERIC );

-- 1:N Relationship (One User -> Many Orders)
CREATE TABLE orders ( 
    id INT PRIMARY KEY, 
    user_id INT REFERENCES users(id) 
);

-- N:M Relationship (Orders have Many Products, Products belong to Many Orders)
-- We build a Pivot table called "order_items"
CREATE TABLE order_items (
    order_id INT REFERENCES orders(id),
    product_id INT REFERENCES products(id),
    quantity INT,
    PRIMARY KEY (order_id, product_id)
);

9. Common Mistakes

  • Creating the Child Table First: You cannot create the employees table if the departments table does not exist yet. You must always construct the Parent tables before the Child tables.
  • Data Type Mismatches: If the Parent Primary Key is a BIGINT, the Child Foreign Key column MUST also be a BIGINT. If you make it a standard INT, PostgreSQL will throw a foreign key constraint error.

10. Best Practices

  • Naming Conventions: Always name your Foreign Key columns as the singular parent table name followed by id (e.g., userid, productid).
  • Index your Foreign Keys: PostgreSQL does NOT automatically index Foreign Keys. To make JOINs fast, you should always manually create an index on every foreign key column (We will cover Indexing in Chapter 18).

11. Exercises

  1. 1. In a blog application, One User writes Many Posts. Which table contains the Foreign Key?
  1. 2. What does ON DELETE CASCADE do?

12. SQL Challenges

Write the DDL to create a reviews table that has a Foreign Key pointing to a products table (product
id). Ensure that if a product is deleted, all its reviews are automatically deleted.
sql
123456
CREATE TABLE reviews (
    review_id SERIAL PRIMARY KEY,
    product_id INTEGER,
    rating INTEGER,
    FOREIGN KEY (product_id) REFERENCES products(product_id) ON DELETE CASCADE
);

13. MCQ Quiz with Answers

Question 1

In database architecture, what is a "Pivot" (or Junction) table used for?

Question 2

By default (without CASCADE), what will PostgreSQL do if you attempt to DELETE a user who currently has 5 active orders pointing to them via a Foreign Key?

14. Interview Questions

  • Q: Explain the concept of Referential Integrity. How do Foreign Keys enforce it?
  • Q: Describe a business scenario where using ON DELETE CASCADE would be extremely dangerous and ill-advised.

15. FAQs

Q: Can a Foreign Key be NULL? A: Yes! If a column is a Foreign Key, it can be NULL (meaning the row currently has no parent). However, if there IS data in it, that data MUST match a valid Primary Key in the parent table.

16. Summary

Foreign Keys are the mortar that holds the bricks of your database together. By establishing strict parent-child relationships and utilizing pivot tables, you can model infinitely complex real-world systems while PostgreSQL automatically guards against data corruption.

17. Next Chapter Recommendation

Our tables are beautifully separated and linked. But when a user loads their dashboard, they don't want a random user_id number; they want the actual names and data from across all tables stitched back together! In Chapter 14: INNER JOIN, LEFT JOIN, RIGHT JOIN, and FULL JOIN, we will master the art of querying across relationships.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·