Detective's Journal
Primary Key vs Foreign Key: The Complete Visual Guide (2026)
February 19, 2026
11 min read
Hristo Bogoev

Primary Key vs Foreign Key: The Complete Visual Guide (2026)

Learn the difference between primary key and foreign key in SQL with visual diagrams, code examples, and practical detective-themed scenarios.

If you've ever stared at a database and wondered why some columns are marked as keys while others aren't, you're not alone. Primary keys and foreign keys are the backbone of relational databases, but most explanations make them sound more complicated than they need to be. Let's fix that.

πŸ’¬Real question from r/SQL
β€œPLEASE explain foreign keys to me like I am six years old”

Quick Answer: Primary Key vs Foreign Key

Here's the TL;DR:

  • Primary key: Unique identifier for each row in a table (like a suspect ID in a criminal database)
  • Foreign key: A reference to a primary key in another table (like case_id in an evidence table linking back to cases)
  • Key difference: Primary keys ensure uniqueness; foreign keys ensure relationships
FeaturePrimary KeyForeign Key
PurposeUniquely identifies each rowLinks to another table
UniquenessMust be uniqueCan have duplicates
NULL allowedNoYes (usually)
Count per tableOnly oneMultiple allowed
Automatically indexedYesNo (but recommended)

Quick reference comparison

What is a Primary Key?

A primary key is a column (or combination of columns) that uniquely identifies each row in a table. Think of it like a suspect ID in a criminal database: no two suspects share the same ID, and every suspect must have one.

Four rules of primary keys:

  1. Unique: No duplicates allowed
  2. Not null: Every row must have a value
  3. Immutable: Should rarely change (changing IDs causes chaos)
  4. Indexed: Automatically indexed for fast lookups
CREATE TABLECREATE TABLE suspects (
Define a new table
PRIMARY KEYsuspect_id INT PRIMARY KEY,
This column uniquely identifies each suspect
columnsname VARCHAR(100), age INT, last_seen DATE );
Other suspect information

CREATE TABLE with primary key

You can also define a composite primary key using multiple columns. This is common in junction tables:

Composite Primary Key Example:

CREATE TABLE case_suspects (
  case_id INT,
  suspect_id INT,
  role VARCHAR(50),
  PRIMARY KEY (case_id, suspect_id)
);

The combination of case_id + suspect_id must be unique.

What is a Foreign Key?

A foreign key is a column that references the primary key of another table. It creates a relationship between tables and enforces referential integrity (meaning you can't link to something that doesn't exist).

πŸ’¬Community analogy from r/explainlikeimfive
β€œThink of it like social security numbers. Your SSN is your primary key. When a bank stores your account, they use your SSN as a foreign key to link back to you.”

In a detective database, evidence belongs to a specific case. The case_id in the evidence table is a foreign key that references the case_id primary key in the cases table:

CREATE TABLECREATE TABLE evidence (
Evidence table stores clues
PRIMARY KEYevidence_id INT PRIMARY KEY,
Each piece of evidence has unique ID
FOREIGN KEYcase_id INT, description TEXT, FOREIGN KEY (case_id) REFERENCES cases(case_id)
Links this evidence to a specific case

CREATE TABLE with foreign key

Unlike primary keys, foreign keys can have duplicates (many pieces of evidence can belong to the same case) and can be NULL (evidence might not be assigned to a case yet).

Want to practice JOINing tables with primary and foreign keys? SQLNoir's detective cases challenge you to query across multiple related tables to crack mysteries.

How Primary and Foreign Keys Work Together

Keys create relationships between tables. In a detective database, you might have suspects, cases, evidence, and interviews. Here's how they connect:

πŸ“‹ suspects
  • πŸ”‘suspect_id
  • name
  • age
  • last_seen
πŸ“‹ cases
  • πŸ”‘case_id
  • title
  • status
  • lead_detective
πŸ“‹ evidence
  • πŸ”‘evidence_id
  • case_id
  • description
  • found_date
πŸ“‹ interviews
  • πŸ”‘interview_id
  • case_id
  • suspect_id
  • transcript
cases.case_id→evidence.case_id1:N(One case has many pieces of evidence)
cases.case_id→interviews.case_id1:N(One case has many interviews)
suspects.suspect_id→interviews.suspect_id1:N(One suspect can have many interviews)

Detective database schema showing primary and foreign key relationships

πŸ”The Key Insight
Primary keys are the β€œanchor” that other tables reference. Foreign keys are the β€œlinks” that create the chain. Without this relationship, you'd need to duplicate data everywhere.

Here's the complete schema in SQL:

Complete Detective Database:

-- Suspects table (primary key: suspect_id)
CREATE TABLE suspects (
  suspect_id INT PRIMARY KEY,
  name VARCHAR(100),
  age INT,
  last_seen DATE
);

-- Cases table (primary key: case_id)
CREATE TABLE cases (
  case_id INT PRIMARY KEY,
  title VARCHAR(200),
  status VARCHAR(50),
  lead_detective VARCHAR(100)
);

-- Evidence table (foreign key references cases)
CREATE TABLE evidence (
  evidence_id INT PRIMARY KEY,
  case_id INT,
  description TEXT,
  found_date DATE,
  FOREIGN KEY (case_id) REFERENCES cases(case_id)
);

-- Interviews table (foreign keys reference both cases AND suspects)
CREATE TABLE interviews (
  interview_id INT PRIMARY KEY,
  case_id INT,
  suspect_id INT,
  transcript TEXT,
  FOREIGN KEY (case_id) REFERENCES cases(case_id),
  FOREIGN KEY (suspect_id) REFERENCES suspects(suspect_id)
);

Referential Integrity: What Happens When You Delete Data?

Here's where it gets interesting. What happens when you delete a case that has linked evidence? The foreign key constraint controls this behavior:

  • CASCADE: Delete the parent, and all child rows are automatically deleted too
  • RESTRICT: Prevent deletion if child rows exist (default in most databases)
  • SET NULL: Set the foreign key to NULL when the parent is deleted
  • NO ACTION: Similar to RESTRICT, but checked at end of transaction
πŸ—‘οΈDELETE FROM cases WHERE case_id = 1
πŸ”Check for linked evidence
πŸ’₯CASCADE: Delete evidence too
🚫RESTRICT: Block the delete
❓SET NULL: Orphan the evidence

What happens when you delete a parent row depends on your ON DELETE setting

Here's how you define these behaviors:

ON DELETE CASCADE:

CREATE TABLE evidence (
  evidence_id INT PRIMARY KEY,
  case_id INT,
  description TEXT,
  FOREIGN KEY (case_id) REFERENCES cases(case_id)
    ON DELETE CASCADE
);

-- Now when you delete a case:
DELETE FROM cases WHERE case_id = 1;
-- All evidence linked to case 1 is automatically deleted!

ON DELETE RESTRICT (safer):

CREATE TABLE evidence (
  evidence_id INT PRIMARY KEY,
  case_id INT,
  description TEXT,
  FOREIGN KEY (case_id) REFERENCES cases(case_id)
    ON DELETE RESTRICT
);

-- Now when you try to delete a case with evidence:
DELETE FROM cases WHERE case_id = 1;
-- ERROR: Cannot delete - dependent records exist!
❌Before: DELETE FROM cases WHERE case_id = 1
cases: [(1, 'Miami Murder')]
evidence: [(1, 1, 'Fingerprint'), (2, 1, 'Weapon')]

β€’Case 1 exists with 2 pieces of evidence linked to it

βœ…After: With ON DELETE CASCADE
cases: (empty)
evidence: (empty)

β€’Case 1 deleted

β€’Both evidence rows automatically removed

β€’No orphaned records

CASCADE deletes cascade to all related child rows

⚠️Danger Zone
CASCADE is powerful but dangerous. One wrong DELETE can wipe out years of related data. Use RESTRICT in production unless you have a specific reason for CASCADE.

Primary Key vs Foreign Key: Full Comparison

Here's the comprehensive side-by-side breakdown:

AspectPrimary KeyForeign Key
PurposeUniquely identifies rowsCreates relationships between tables
UniquenessMust be unique (no duplicates)Duplicates allowed
NULL valuesNever allowedAllowed (unless constrained)
Count per tableExactly oneZero or more
Automatically indexedYes (always)No (must add manually)
References another tableNoYes (references a primary key)
Can be compositeYes (multiple columns)Yes (multiple columns)
ModificationDifficult to changeCan be updated if new value exists
Delete behaviorCannot delete if referencedConfigurable (CASCADE, RESTRICT, etc.)
Performance impactSpeeds up lookupsSlows writes (integrity checks)

10-point comparison of primary and foreign keys

Case File #003πŸ”

The Miami Marina Murder

●●○Intermediate

Put your primary and foreign key knowledge to work. Join suspects, interviews, and hotel check-ins to find the killer.

Start Investigation

Common Mistakes (And How to Avoid Them)

Mistake 1: Forgetting the Foreign Key Constraint

Just because a column is named customer_id doesn't make it a foreign key. You need to explicitly define the constraint:

❌❌ Wrong: No foreign key constraint
CREATE TABLE orders (
  order_id INT PRIMARY KEY,
  customer_id INT  -- No constraint!
);

β€’Can insert orders with non-existent customer_id

β€’Orphaned records possible

β€’Data integrity compromised

βœ…βœ… Right: Foreign key constraint enforced
CREATE TABLE orders (
  order_id INT PRIMARY KEY,
  customer_id INT,
  FOREIGN KEY (customer_id) 
    REFERENCES customers(customer_id)
);

β€’Database enforces valid customer_id

β€’Cannot insert invalid references

β€’Data integrity guaranteed

Always define foreign key constraints explicitly

Mistake 2: Using Business Data as Primary Key

Using email addresses, phone numbers, or social security numbers as primary keys seems convenient but causes problems when that data changes:

❌ Wrong:

CREATE TABLE customers (
  email VARCHAR(255) PRIMARY KEY,  -- Bad idea!
  name VARCHAR(100)
);

-- What happens when a customer changes their email?
-- You have to update EVERY table that references it!

βœ… Right:

CREATE TABLE customers (
  customer_id INT PRIMARY KEY AUTO_INCREMENT,
  email VARCHAR(255) UNIQUE,  -- Unique constraint, not primary key
  name VARCHAR(100)
);

-- Email can change; customer_id stays constant forever.

Mistake 3: Not Indexing Foreign Key Columns

Primary keys are automatically indexed, but foreign keys are not. This means JOINs on foreign keys can be slow on large tables:

-- After creating your table with foreign key:
CREATE INDEX idx_evidence_case_id ON evidence(case_id);
CREATE INDEX idx_interviews_case_id ON interviews(case_id);
CREATE INDEX idx_interviews_suspect_id ON interviews(suspect_id);

Index foreign key columns for faster JOINs and constraint checking.

πŸ•΅οΈPro Tip
Most database tools show you which columns are indexed. Check your foreign keys. If they're not indexed and you JOIN on them frequently, add indexes.

Test Your Understanding

πŸ”‘ Primary Key vs Foreign Key Quiz

Q1.A primary key column can contain NULL values.

Q2.How many foreign keys can a single table have?

Q3.What happens with ON DELETE CASCADE when you delete a parent row?

Q4.Why should you create an index on foreign key columns?

FAQ

Can a foreign key also be a primary key?

Yes! In junction tables for many-to-many relationships, the composite primary key often consists of two foreign keys. Example: a case_suspects table with (case_id, suspect_id) as the composite primary key, where both columns are also foreign keys.

Can a table have multiple primary keys?

No. A table can have only ONE primary key. However, that primary key can be a COMPOSITE key made of multiple columns. You might hear β€œmultiple primary keys” but this is incorrect terminology.

What is a composite key?

A composite key is a primary key made of two or more columns. All columns together must be unique. Common in junction tables: PRIMARY KEY (order_id, product_id).

Do foreign keys hurt database performance?

Foreign keys add overhead on INSERT, UPDATE, and DELETE because the database must check referential integrity. However, this overhead is usually small and the data integrity benefits outweigh the cost. Index your foreign key columns to minimize the impact.

Is a foreign key required?

No. Foreign keys are optional but strongly recommended. Without them, the database allows orphaned records (evidence linked to non-existent cases). You CAN skip them, but your data quality will suffer.

πŸ’¬Common frustration from r/learnprogramming
β€œI keep seeing these terms but nobody explains WHY you'd use them, just WHAT they are”

The WHY is simple: primary keys let you find specific rows instantly, and foreign keys let you connect related data without duplicating it. Without keys, you'd either have massive duplication or no way to link your data together.

Ready to practice with primary and foreign keys?

SQLNoir's detective cases let you query across related tables to solve mysteries. No signup required for beginner cases.

Start Your Investigation β†’

Ready to start your next investigation?

Jump into the SQLNoir case files and put these tips to work.