Loading learning content...
Everything we've studied so far—superkeys, candidate keys, primary keys, alternate keys—has focused on identification within a single relation. But the true power of the relational model lies in its ability to represent relationships between relations.
Consider a simple business scenario: An order belongs to a customer. In object-oriented terms, we'd embed a Customer object inside an Order object. But relational databases don't embed—they reference. The Order table contains a reference to the Customer table.
This reference mechanism is the foreign key—arguably the most important structural concept in relational database design. Foreign keys transform isolated tables into an interconnected web of data, enabling complex queries, maintaining data consistency, and preventing orphaned records.
By the end of this page, you will understand the formal definition of foreign keys and referential integrity, master foreign key implementation including referential actions (CASCADE, SET NULL, etc.), appreciate foreign key design patterns and their implications, and recognize the relationship between foreign keys and relationship cardinality.
A foreign key is a set of attributes in one relation (the referencing relation) that references the primary key (or a candidate key) of another relation (the referenced relation). The foreign key establishes a link between tuples in the two relations.
Mathematical formalization:
Let R₁(A, B, C, D) and R₂(X, Y, Z) be two relation schemas where {X} is the primary key of R₂.
A foreign key from R₁ to R₂ on attribute B exists if:
B in R₁ and X in R₂ are domain compatible (same or compatible data types)t₁ ∈ r(R₁), either:
t₁[B] is NULL, ort₂ ∈ r(R₂) such that t₁[B] = t₂[X]This constraint is called referential integrity.
Terminology:
| Term | Definition | Example |
|---|---|---|
| Referencing relation (child) | The table containing the foreign key | Order (contains CustomerID) |
| Referenced relation (parent) | The table being referred to | Customer (has CustomerID as PK) |
| Foreign key attribute(s) | The column(s) holding the reference | Order.CustomerID |
| Referenced key | The key being referenced (usually PK) | Customer.CustomerID |
Example:
Customer(CustomerID, Name, Email)
^^^^^^^^^^^ PK
Order(OrderID, OrderDate, CustomerID, TotalAmount)
^^^^^^^ PK ^^^^^^^^^^^ FK → Customer.CustomerID
The Order.CustomerID foreign key ensures every order is associated with an existing customer.
Unlike primary and alternate keys, foreign keys do NOT require uniqueness. Many orders can reference the same customer—that's the point! The CustomerID in Order can appear in multiple tuples. Foreign keys enforce existence (referential integrity) not uniqueness.
Foreign keys exist to enforce referential integrity—one of the fundamental constraints of the relational model alongside entity integrity.
If a foreign key exists in a relation, its value must either be NULL (if allowed) or it must match a primary key value in the referenced relation. No foreign key can reference a non-existent primary key value.
What referential integrity prevents:
Example: Referential Integrity Violations
Customer Table:
| CustomerID | Name |
|------------|--------|
| C001 | Alice |
| C002 | Bob |
Order Table:
| OrderID | CustomerID | Amount |
|---------|------------|--------|
| O001 | C001 | 150.00 | ← Valid: C001 exists
| O002 | C002 | 75.50 | ← Valid: C002 exists
| O003 | C003 | 200.00 | ← VIOLATION: C003 doesn't exist!
The DBMS will reject the insertion of O003 because CustomerID 'C003' doesn't exist in the Customer table.
Important operations affected:
| Operation | Referential Integrity Check | Possible Violation |
|---|---|---|
| INSERT into child | Does FK value exist in parent? | Inserting order for non-existent customer |
| UPDATE child FK | Does new FK value exist in parent? | Changing order to non-existent customer |
| DELETE from parent | Are there child rows referencing this? | Deleting customer with existing orders |
| UPDATE parent PK | Are there child rows referencing old value? | Changing customer ID that orders reference |
SQL provides the FOREIGN KEY constraint to establish and enforce referential relationships. Multiple syntax forms exist for different scenarios.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
-- First, create the parent (referenced) tableCREATE TABLE Customer ( CustomerID INT PRIMARY KEY, Name VARCHAR(100) NOT NULL, Email VARCHAR(255) UNIQUE NOT NULL); -- Inline foreign key constraint (single column)CREATE TABLE Order_V1 ( OrderID INT PRIMARY KEY, OrderDate DATE NOT NULL, CustomerID INT REFERENCES Customer(CustomerID), -- Inline FK TotalAmount DECIMAL(10,2) NOT NULL); -- Table-level foreign key constraintCREATE TABLE Order_V2 ( OrderID INT PRIMARY KEY, OrderDate DATE NOT NULL, CustomerID INT NOT NULL, TotalAmount DECIMAL(10,2) NOT NULL, FOREIGN KEY (CustomerID) REFERENCES Customer(CustomerID)); -- Named foreign key constraint (recommended)CREATE TABLE Order_V3 ( OrderID INT PRIMARY KEY, OrderDate DATE NOT NULL, CustomerID INT NOT NULL, TotalAmount DECIMAL(10,2) NOT NULL, CONSTRAINT fk_order_customer FOREIGN KEY (CustomerID) REFERENCES Customer(CustomerID)); -- Composite foreign key (referencing composite primary key)CREATE TABLE Course ( DepartmentCode VARCHAR(10), CourseNumber INT, CourseName VARCHAR(100) NOT NULL, PRIMARY KEY (DepartmentCode, CourseNumber)); CREATE TABLE Section ( SectionID INT PRIMARY KEY, DepartmentCode VARCHAR(10) NOT NULL, CourseNumber INT NOT NULL, Semester VARCHAR(20) NOT NULL, InstructorID INT NOT NULL, CONSTRAINT fk_section_course FOREIGN KEY (DepartmentCode, CourseNumber) REFERENCES Course(DepartmentCode, CourseNumber)); -- Adding FK to existing tableALTER TABLE Order_V1ADD CONSTRAINT fk_order_customer FOREIGN KEY (CustomerID) REFERENCES Customer(CustomerID);Use descriptive names like 'fk_childtable_parenttable' or 'fk_childtable_column'. Example: 'fk_order_customer' or 'fk_order_customerid'. This makes constraint management and error message interpretation much easier.
When a referenced (parent) row is deleted or updated, the DBMS must decide what happens to the referencing (child) rows. SQL provides referential actions to specify this behavior.
| Action | ON DELETE Behavior | ON UPDATE Behavior | Use Case |
|---|---|---|---|
| CASCADE | Delete all child rows | Update FK in all child rows | Dependent data that shouldn't exist without parent |
| SET NULL | Set FK to NULL in child rows | Set FK to NULL in child rows | Optional relationships; child can exist independently |
| SET DEFAULT | Set FK to default value | Set FK to default value | Rare; when default value is meaningful |
| RESTRICT | Prevent deletion if children exist | Prevent update if children exist | Strict referential integrity |
| NO ACTION | Same as RESTRICT (SQL standard) | Same as RESTRICT (SQL standard) | Default in most DBMSs |
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
-- CASCADE: Deleting a customer deletes all their ordersCREATE TABLE Order_Cascade ( OrderID INT PRIMARY KEY, CustomerID INT NOT NULL, OrderDate DATE NOT NULL, CONSTRAINT fk_order_customer FOREIGN KEY (CustomerID) REFERENCES Customer(CustomerID) ON DELETE CASCADE ON UPDATE CASCADE);-- DELETE FROM Customer WHERE CustomerID = 1;-- → All orders for customer 1 are automatically deleted -- SET NULL: Deleting a customer sets orders to "no customer"CREATE TABLE Order_SetNull ( OrderID INT PRIMARY KEY, CustomerID INT, -- Must be nullable! OrderDate DATE NOT NULL, CONSTRAINT fk_order_customer FOREIGN KEY (CustomerID) REFERENCES Customer(CustomerID) ON DELETE SET NULL ON UPDATE SET NULL);-- DELETE FROM Customer WHERE CustomerID = 1;-- → All orders for customer 1 now have CustomerID = NULL -- RESTRICT: Cannot delete customer if orders existCREATE TABLE Order_Restrict ( OrderID INT PRIMARY KEY, CustomerID INT NOT NULL, OrderDate DATE NOT NULL, CONSTRAINT fk_order_customer FOREIGN KEY (CustomerID) REFERENCES Customer(CustomerID) ON DELETE RESTRICT ON UPDATE RESTRICT);-- DELETE FROM Customer WHERE CustomerID = 1;-- → ERROR if customer 1 has any orders -- Mixed actions (common pattern)CREATE TABLE Order_Mixed ( OrderID INT PRIMARY KEY, CustomerID INT NOT NULL, OrderDate DATE NOT NULL, CONSTRAINT fk_order_customer FOREIGN KEY (CustomerID) REFERENCES Customer(CustomerID) ON DELETE RESTRICT -- Prevent accidental data loss ON UPDATE CASCADE -- Allow ID corrections to propagate);ON DELETE CASCADE can cause massive unintended data loss. A single DELETE statement could cascade through multiple tables, removing thousands of rows. Use CASCADE only when the business logic genuinely requires it (e.g., order line items when an order is deleted). For important data, prefer RESTRICT and require explicit deletion of child rows.
A special but common case occurs when a table references itself—the foreign key points to the primary key of the same table. This models hierarchical or recursive relationships.
A self-referencing (or recursive) foreign key is a foreign key that references the primary key of the same table. This creates a parent-child relationship within a single table, commonly used for hierarchies like organizational structures, categories, or bill-of-materials.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
-- Employee hierarchy (manager-subordinate relationship)CREATE TABLE Employee ( EmployeeID INT PRIMARY KEY, Name VARCHAR(100) NOT NULL, Title VARCHAR(100) NOT NULL, ManagerID INT, -- Self-referencing FK (nullable for top-level) CONSTRAINT fk_employee_manager FOREIGN KEY (ManagerID) REFERENCES Employee(EmployeeID) ON DELETE SET NULL -- If manager leaves, subordinates remain); -- Sample data showing hierarchy:INSERT INTO Employee (EmployeeID, Name, Title, ManagerID) VALUES(1, 'Alice Chen', 'CEO', NULL), -- Top level, no manager(2, 'Bob Smith', 'VP Engineering', 1), -- Reports to Alice(3, 'Carol Jones', 'VP Sales', 1), -- Reports to Alice(4, 'David Brown', 'Senior Engineer', 2), -- Reports to Bob(5, 'Eve Wilson', 'Engineer', 2), -- Reports to Bob(6, 'Frank Lee', 'Sales Manager', 3); -- Reports to Carol -- Query: Find all employees with their manager namesSELECT e.Name AS Employee, e.Title, m.Name AS ManagerFROM Employee eLEFT JOIN Employee m ON e.ManagerID = m.EmployeeID; -- Category hierarchy (e.g., product categories)CREATE TABLE Category ( CategoryID INT PRIMARY KEY, CategoryName VARCHAR(100) NOT NULL, ParentCategoryID INT, CONSTRAINT fk_category_parent FOREIGN KEY (ParentCategoryID) REFERENCES Category(CategoryID) ON DELETE CASCADE -- Deleting parent deletes subcategories); -- Bill of Materials (BOM) - recursive assembly structureCREATE TABLE Component ( ComponentID INT PRIMARY KEY, ComponentName VARCHAR(100) NOT NULL, UnitCost DECIMAL(10,2) NOT NULL); CREATE TABLE Assembly ( ParentComponentID INT, ChildComponentID INT, Quantity INT NOT NULL, PRIMARY KEY (ParentComponentID, ChildComponentID), FOREIGN KEY (ParentComponentID) REFERENCES Component(ComponentID), FOREIGN KEY (ChildComponentID) REFERENCES Component(ComponentID), -- Prevent circular references with CHECK (basic) CHECK (ParentComponentID != ChildComponentID));Foreign keys are the physical implementation of relationships between entities. The placement and constraints of foreign keys directly correspond to relationship cardinality (1:1, 1:N, M:N).
Implementing each cardinality:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
-- ===================================================-- ONE-TO-MANY (1:N): Customer has many Orders-- FK on the "many" side references the "one" side-- ===================================================CREATE TABLE Customer ( CustomerID INT PRIMARY KEY, Name VARCHAR(100) NOT NULL); CREATE TABLE CustomerOrder ( OrderID INT PRIMARY KEY, OrderDate DATE NOT NULL, CustomerID INT NOT NULL, -- FK on the "many" side FOREIGN KEY (CustomerID) REFERENCES Customer(CustomerID));-- One customer → many orders-- Each order → exactly one customer -- ===================================================-- ONE-TO-ONE (1:1): Employee has one ParkingSpot-- FK with UNIQUE constraint creates 1:1-- ===================================================CREATE TABLE Employee ( EmployeeID INT PRIMARY KEY, Name VARCHAR(100) NOT NULL); CREATE TABLE ParkingSpot ( SpotID INT PRIMARY KEY, Location VARCHAR(50) NOT NULL, EmployeeID INT UNIQUE, -- UNIQUE makes it 1:1 FOREIGN KEY (EmployeeID) REFERENCES Employee(EmployeeID));-- One employee → at most one parking spot-- One parking spot → at most one employee -- Alternative 1:1 - FK in either table worksCREATE TABLE EmployeeWithParking ( EmployeeID INT PRIMARY KEY, Name VARCHAR(100) NOT NULL, ParkingSpotID INT UNIQUE, -- FK with UNIQUE FOREIGN KEY (ParkingSpotID) REFERENCES ParkingSpot(SpotID)); -- ===================================================-- MANY-TO-MANY (M:N): Students enroll in Courses-- Junction table with two FKs, composite PK-- ===================================================CREATE TABLE Student ( StudentID INT PRIMARY KEY, Name VARCHAR(100) NOT NULL); CREATE TABLE Course ( CourseID INT PRIMARY KEY, CourseName VARCHAR(100) NOT NULL); CREATE TABLE Enrollment ( StudentID INT NOT NULL, CourseID INT NOT NULL, EnrollmentDate DATE NOT NULL, Grade CHAR(2), PRIMARY KEY (StudentID, CourseID), -- Composite PK FOREIGN KEY (StudentID) REFERENCES Student(StudentID), FOREIGN KEY (CourseID) REFERENCES Course(CourseID));-- One student → many courses (via Enrollment)-- One course → many students (via Enrollment)| Cardinality | FK Placement | Additional Constraint | Example |
|---|---|---|---|
| One-to-Many (1:N) | FK on N-side | None needed | Order.CustomerID → Customer |
| One-to-One (1:1) | FK on either side | UNIQUE on FK column | ParkingSpot.EmployeeID UNIQUE |
| Many-to-Many (M:N) | Junction table with 2 FKs | Composite PK or UNIQUE | Enrollment(StudentID, CourseID) |
Effective foreign key design requires balancing data integrity, performance, and practical maintainability. Here are key guidelines from experienced database practitioners.
12345678910111213141516171819202122232425262728293031
-- Foreign key columns should be indexed for performance-- Most DBMSs don't auto-create these indexes! CREATE TABLE Order_Optimized ( OrderID INT PRIMARY KEY, CustomerID INT NOT NULL, ProductID INT NOT NULL, OrderDate DATE NOT NULL, Quantity INT NOT NULL, CONSTRAINT fk_order_customer FOREIGN KEY (CustomerID) REFERENCES Customer(CustomerID) ON DELETE RESTRICT, CONSTRAINT fk_order_product FOREIGN KEY (ProductID) REFERENCES Product(ProductID) ON DELETE RESTRICT); -- Explicitly create indexes on FK columnsCREATE INDEX idx_order_customer ON Order_Optimized(CustomerID);CREATE INDEX idx_order_product ON Order_Optimized(ProductID); -- Why index FK columns?-- 1. JOIN performance: SELECT * FROM Order JOIN Customer ON ...-- 2. DELETE validation: DELETE FROM Customer WHERE CustomerID = X-- → DBMS must check if any Orders reference this customer-- → Without index: full table scan on Order table-- 3. UPDATE validation: Same as DELETE when updating PKSome high-performance systems (OLTP workloads, data warehouses) omit foreign key constraints at the database level for performance. This shifts integrity enforcement to the application layer. This is a valid trade-off in specific scenarios, but increases risk of data corruption if application bugs exist. Make this choice consciously and document it.
We've comprehensively covered foreign keys—the mechanism that connects relations and enforces referential integrity. This completes our exploration of keys in the relational model. Let's consolidate the key insights:
Module Complete: Keys in the Relational Model
You've now mastered all five key types:
These concepts form the structural backbone of relational database design. Every table you create, every relationship you model, and every query you write builds upon this foundation.
You have completed the Keys module. You can now identify and implement all key types in relational schemas, understand the hierarchy from superkeys to foreign keys, apply proper constraints (UNIQUE, NOT NULL, FOREIGN KEY) for each key type, design relationships using appropriate foreign key patterns, and make informed decisions about referential actions and performance trade-offs. Next, explore integrity constraints to see how these key concepts integrate into the broader data integrity framework.