Surrogate Key vs Natural Key and Alternate Key
The ID Debate Every Schema Designer Must Win
LinkedIn Hook
"Three years ago, a startup I worked with used email as the primary key for their
userstable. Last month, a customer asked to change their email. The migration touched 47 tables, 3 read replicas, and 12 million rows. It took the weekend."Every schema designer eventually runs into the same fork in the road: should the primary key be something meaningful from the real world — an ISBN, an email, a country code — or should it be a meaningless auto-generated number that the database invents out of thin air?
The meaningful key feels elegant. No extra column, no wasted bytes, the data speaks for itself. Until the real world shifts under your feet. ISBNs get reissued. Emails change. Country codes get retired. Social Security numbers get reused. And suddenly your "stable identifier" is propagating updates across every foreign key that referenced it.
The surrogate key — a
bigserialoruuidthe database generates and nothing outside the database ever sees — is the boring answer that quietly wins in production. It is stable forever, it is small, it is fast to join on, and it never changes because the user changed their mind. The natural key does not disappear — it becomes an alternate key with aUNIQUEconstraint, giving you the best of both worlds: the stability of a surrogate and the uniqueness guarantee of the real-world value.In Lesson 2.5, I break down surrogate vs natural keys, the role of alternate keys, and when to use which. If you have ever made a primary key you later regretted, this one is for you.
Read the full lesson -> [link]
#Database #SQL #PostgreSQL #DataModeling #SchemaDesign #InterviewPrep
What You'll Learn
- The difference between a surrogate key (database-generated, meaningless) and a natural key (real-world, meaningful)
- What an alternate key is and how it relates to candidate keys from Lesson 2.3
- Concrete pros and cons of each approach across stability, performance, data leakage, joins, and debuggability
- When to pick a natural key (rare, specific cases) and when to default to a surrogate (almost always)
- How to get the best of both worlds: surrogate PK plus a
UNIQUEconstraint on the natural key - Common traps: mutable natural keys, using SSN as a primary key, and forgetting the alternate key uniqueness constraint
- How to answer the "natural vs surrogate" debate in an interview without sounding dogmatic
The Nickname vs Birth Certificate Analogy — Why Meaningless IDs Win
Imagine two ways to identify every person in a city.
Option A — the nickname. The city keeps a ledger indexed by the name everyone calls you. "Big Mike from Queens", "Sarah the Baker", "Dave with the red truck". The nicknames are meaningful, everyone recognizes them, no extra ID card required. But Mike moves out of Queens. Sarah closes the bakery. Dave sells the truck. Every record referencing the old nickname now points at a person who no longer matches. Worse, a new Mike moves to Queens — do you update the ledger, or is this a different Mike? The nicknames carry information, and information changes.
Option B — the birth certificate number. At birth, the city assigns you a sequential number. The number means nothing to humans — it is not your name, not your address, not your age. It is just #4817293. You carry it forever. Even if you move, change your name, switch jobs, get a new truck, the number never changes. Every record in the city referencing #4817293 still points at you, unambiguously, for your entire life.
The birth certificate number is a surrogate key. It was generated by the system, has no real-world meaning, and is guaranteed stable because no fact about you can invalidate it. The nickname is a natural key — it exists independently of the database, it carries meaning, and it is vulnerable to every shift in the real world it describes.
+---------------------------------------------------------------+
| NICKNAME (NATURAL KEY) |
+---------------------------------------------------------------+
| |
| "Big Mike from Queens" |
| | |
| +-- Mike moves to Brooklyn -> key invalid |
| +-- Another Mike arrives -> collision |
| +-- Mike loses weight -> still "Big"? |
| |
| Meaning = Fragility |
| |
+---------------------------------------------------------------+
+---------------------------------------------------------------+
| BIRTH CERTIFICATE # (SURROGATE KEY) |
+---------------------------------------------------------------+
| |
| #4817293 |
| | |
| +-- Mike moves anywhere -> same # |
| +-- Mike changes his name -> same # |
| +-- Mike changes everything -> same # |
| |
| Meaninglessness = Stability |
| |
+---------------------------------------------------------------+
This analogy maps one-to-one onto the database design question. The rule that falls out of it is simple: the more a value means in the real world, the worse it is as a primary key, because the real world reserves the right to change its mind.
Definitions — Surrogate, Natural, and Alternate Keys
Before we go further, the three terms must be crisp. These are the exact distinctions interviewers probe.
| Term | Definition | Source of Value | Example |
|---|---|---|---|
| Natural Key | A column (or set of columns) whose value already exists in the real world and uniquely identifies the row on its own merits. | Real-world fact (ISBN, email, SSN, country code, ticker symbol). | isbn in a books table. |
| Surrogate Key | A column whose value is generated by the database for the sole purpose of identifying the row. It has no meaning outside the database. | Auto-generated (serial, bigserial, uuid, identity). | id BIGSERIAL in a users table. |
| Alternate Key | A candidate key (from Lesson 2.3) that was not chosen as the primary key but still uniquely identifies the row. Enforced with a UNIQUE constraint. | Either real-world fact or another surrogate. | email UNIQUE in a users table whose PK is id. |
The link to Lesson 2.3 is important: a table can have many candidate keys. You pick one as the primary key — typically the surrogate — and every other candidate key becomes an alternate key, enforced by a UNIQUE constraint. Alternate keys are not second-class citizens; they still guarantee uniqueness, they are still indexed, and they are the right way to look up rows by the values humans actually know (email, username, slug).
+---------------------------------------------------------------+
| CANDIDATE KEYS OF users TABLE |
+---------------------------------------------------------------+
| |
| Candidate #1: id (surrogate, bigserial) |
| Candidate #2: email (natural, user-supplied) |
| Candidate #3: username (natural, user-supplied) |
| |
| Choose ONE as PRIMARY KEY: id |
| The rest become ALTERNATE KEYS: email, username |
| (UNIQUE constraints) |
| |
+---------------------------------------------------------------+
Side-by-Side CREATE TABLE — Natural PK vs Surrogate PK
The cleanest way to see the difference is to write both. Here is a books table using a natural primary key (ISBN) and a users table using a surrogate primary key (bigserial). Both are runnable PostgreSQL.
Natural Key: books with ISBN as PK
-- Natural primary key: ISBN is a globally-assigned 13-digit identifier
-- for every published book. It already exists, it is already unique,
-- and it is printed on the book itself. This is one of the few cases
-- where a natural key is defensible.
CREATE TABLE books (
isbn CHAR(13) PRIMARY KEY, -- natural PK
title TEXT NOT NULL,
author TEXT NOT NULL,
published DATE NOT NULL,
price_cents INTEGER NOT NULL CHECK (price_cents >= 0)
);
INSERT INTO books (isbn, title, author, published, price_cents) VALUES
('9780132350884', 'Clean Code', 'Robert C. Martin', '2008-08-01', 3999),
('9780134685991', 'Effective Java', 'Joshua Bloch', '2017-12-27', 4599),
('9780201633610', 'Design Patterns', 'Erich Gamma', '1994-10-31', 5499);
SELECT isbn, title FROM books ORDER BY title;
-- Output:
-- isbn | title
-- ----------------+----------------
-- 9780132350884 | Clean Code
-- 9780201633610 | Design Patterns
-- 9780134685991 | Effective Java
ISBN is a reasonable natural key because (a) it is assigned by an outside authority (the ISBN agency), (b) it is immutable once assigned, and (c) it is already how the publishing world identifies books. Even here there are caveats — ISBN-10 vs ISBN-13, reissues with new ISBNs — but it comes as close as a natural key ever does to the ideal.
Surrogate Key: users with bigserial as PK
-- Surrogate primary key: id is generated by the database. It has no
-- meaning. Email is still unique (alternate key), but it is not the PK
-- because emails CHANGE — marriage, job change, typo correction.
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY, -- surrogate PK
email TEXT NOT NULL UNIQUE, -- alternate key
username TEXT NOT NULL UNIQUE, -- alternate key
display_name TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
INSERT INTO users (email, username, display_name) VALUES
('ada@example.com', 'ada', 'Ada Lovelace'),
('alan@example.com', 'alan', 'Alan Turing'),
('grace@example.com', 'grace', 'Grace Hopper');
SELECT id, email, username FROM users ORDER BY id;
-- Output:
-- id | email | username
-- ----+--------------------+----------
-- 1 | ada@example.com | ada
-- 2 | alan@example.com | alan
-- 3 | grace@example.com | grace
Notice what the surrogate approach buys us. If Ada changes her email from ada@example.com to ada.lovelace@newjob.com, it is a single UPDATE on one row:
UPDATE users SET email = 'ada.lovelace@newjob.com' WHERE id = 1;
-- UPDATE 1
-- Nothing else changes. Zero foreign keys need updating.
If email had been the primary key, every table with a foreign key to users(email) — orders, sessions, audit logs, comments — would need a cascading update. With millions of rows, that is a multi-hour migration. With a surrogate key, it is a single write to a single row.
The Alternate Key Pattern — Surrogate PK + UNIQUE Natural Columns
The critical insight most juniors miss is that choosing a surrogate key does not mean giving up uniqueness on the natural values. The natural key becomes an alternate key via a UNIQUE constraint, and the database still guarantees that no two users can share an email.
-- Full example: surrogate PK, two alternate keys, one composite
-- alternate key for good measure.
CREATE TABLE accounts (
id BIGSERIAL PRIMARY KEY, -- surrogate PK
email TEXT NOT NULL,
phone TEXT NOT NULL,
tenant_id INTEGER NOT NULL,
external_ref TEXT NOT NULL,
-- Alternate keys: each of these alone uniquely identifies a row
CONSTRAINT accounts_email_key UNIQUE (email),
CONSTRAINT accounts_phone_key UNIQUE (phone),
-- Composite alternate key: (tenant_id, external_ref) is unique
-- per tenant, even though external_ref alone is not globally unique.
CONSTRAINT accounts_tenant_ext_key UNIQUE (tenant_id, external_ref)
);
-- Attempting to insert a duplicate email fails at the alternate key:
INSERT INTO accounts (email, phone, tenant_id, external_ref)
VALUES ('sam@example.com', '+1-555-0100', 1, 'ext-001');
-- INSERT 0 1
INSERT INTO accounts (email, phone, tenant_id, external_ref)
VALUES ('sam@example.com', '+1-555-0200', 2, 'ext-002');
-- ERROR: duplicate key value violates unique constraint "accounts_email_key"
-- DETAIL: Key (email)=(sam@example.com) already exists.
The surrogate id is the stable internal identifier used by foreign keys. The alternate keys are how the outside world looks up rows (WHERE email = ?, WHERE phone = ?). Both are indexed, both are enforced, and you get stability plus real-world uniqueness for the price of one extra column.
Pros and Cons — Concrete Scenarios
The abstract trade-off list is not enough; you need to see how each property plays out in real systems.
| Concern | Natural Key | Surrogate Key |
|---|---|---|
| Stability | Fragile — changes when the real world changes (email, SSN, ISBN reissue). | Immutable — the database owns the value, nothing outside can invalidate it. |
| Size / Performance | Often wide (VARCHAR(255) email, 13-char ISBN) -> larger indexes, slower joins. | Compact (BIGINT = 8 bytes) -> smaller indexes, faster joins. |
| Data Leakage | PK appears in URLs, logs, exports — leaks real data (email, SSN). | PK is meaningless (42), safe to expose (though still use UUIDs for public APIs if enumeration matters). |
| Joins | Every FK duplicates the natural key across many tables — wastes space and creates update storms. | FK is a single BIGINT regardless of how wide the natural key is. |
| Debugging | WHERE email = 'x' is self-documenting — you can read raw rows and understand them. | WHERE id = 42 tells you nothing — you always need a join to make sense of data. |
| Write Amplification on Changes | A single "user changed email" touches every dependent table. | A single UPDATE users SET email = ... touches one row. |
| Uniqueness Enforcement | Built into the PK for free. | Requires a separate UNIQUE constraint on the natural column. |
| Replication / Merging | Safe to merge two databases — same natural key means same entity. | Requires a UUID or careful id-space partitioning to avoid collisions. |
| Human Memorability | Emails, usernames, and slugs are memorable. | Numbers are not — you always need a lookup. |
Scenario 1 — The Email Change Nightmare
A users table uses email as the PK. Ada gets married, changes her email. The DBA runs:
UPDATE users SET email = 'ada.lovelace@newdomain.com' WHERE email = 'ada@example.com';
Except — 41 other tables have user_email foreign keys pointing at her old address. Every one of them must be updated in the same transaction, or the foreign keys break. On a table with 80 million rows and 12 indexes, this migration locks the table for minutes. With a surrogate key, the same operation is a single-row update and zero foreign keys need to move.
Scenario 2 — The ISBN Reissue
A book is reprinted and the publisher assigns it a new ISBN-13 (this really happens — same content, new ISBN). If ISBN is the PK, you now have a fundamental identity problem: is the new row the "same book"? Every review, rating, and purchase record for the old ISBN is now orphaned. With a surrogate book_id, the ISBN is just a column you can update to the new value.
Scenario 3 — The SSN Leak
An early-stage fintech uses SSN as the primary key of its customers table. Six months later a security audit finds SSN values in application logs, URLs, query parameters, backup files, and the internal admin UI. Removing them takes weeks because the PK is everywhere. Using a surrogate customer_id from day one would have contained the SSN to a single encrypted column that never appears in URLs.
Scenario 4 — The Join Cost
A table joins orders to users 200,000 times per second. With an INTEGER user id, the index is compact and joins are served from cache. With a VARCHAR(255) email as the join key, the index is 30 times larger, cache hit rates drop, and query latency climbs. The performance gap is not hypothetical — it is the difference between 2 ms and 30 ms on hot queries.
When to Use Which — Guidance
Despite the list above, the honest answer is not "always use surrogate keys." There are specific cases where a natural key is correct. Here is the decision tree.
+---------------------------------------------------------------+
| DECISION TREE: NATURAL vs SURROGATE |
+---------------------------------------------------------------+
| |
| Is the value GLOBALLY unique AND IMMUTABLE |
| AND assigned by an external authority |
| AND compact (<= 16 bytes) AND never sensitive? |
| |
| YES -> consider a NATURAL key |
| NO -> use a SURROGATE key + natural as alternate |
| |
| Examples of acceptable NATURAL keys: |
| - ISO country codes (US, GB, JP) in a reference table |
| - Currency codes (USD, EUR) |
| - 2-letter US state codes |
| - Pure junction tables: (user_id, role_id) composite PK |
| |
| Examples of BAD natural keys (always use surrogate): |
| - Email, username, phone number (mutable) |
| - SSN, credit card, passport (sensitive) |
| - Company name, product name (mutable) |
| - ISBN, VIN (reissued, arguable) |
| |
+---------------------------------------------------------------+
Default rule: when in doubt, use a surrogate key. The cases where a natural key is clearly correct are narrow: small, stable reference tables (countries, currencies) and composite primary keys on pure junction tables (user_roles(user_id, role_id)). Every other table in your schema should have a bigserial or uuid primary key with the natural values enforced as alternate keys via UNIQUE constraints.
Napkin AI Visual Prompt: "Dark gradient (#0a0f1f -> #111a2e). Split comparison: LEFT side labeled 'Natural Key (email)' shows a users table with email as PK and a spiderweb of foreign-key arrows to 8 other tables, all highlighted in rose (#ff5c8a) with a cracked 'UPDATE STORM' warning. RIGHT side labeled 'Surrogate Key (id)' shows a users table with id as PK, a small sky-blue (#4fc3f7) email column marked 'UNIQUE', and clean thin FK arrows to the same 8 tables. White monospace labels. Sky-blue arrow at the bottom pointing from surrogate id to 'ONE ROW UPDATED' when email changes."
Common Mistakes
1. Using a mutable natural key as the primary key.
Email, username, phone number, and company name all seem stable until they are not. The moment a user changes their email, every foreign key referencing the old value must be updated in lockstep, or the constraint breaks. The damage is proportional to how many tables reference the PK — and that number only grows over time. The fix is to use a surrogate key from day one and let the natural column be an alternate key with UNIQUE. Changing the email becomes a single-row update with no foreign key fan-out.
2. Using SSN, credit card, or passport number as a primary key.
Primary keys leak. They appear in URLs (/users/123-45-6789), log lines, error messages, query parameters, exports, backups, and debug screens. Using a sensitive real-world identifier as the PK spreads it across your entire system surface area and creates a compliance nightmare (GDPR, PCI, HIPAA). The fix is a surrogate id with the sensitive value stored in one encrypted column, referenced by nothing, and redacted from logs. The sensitive value never becomes a join key.
3. Picking a surrogate PK but forgetting the UNIQUE on the natural column.
A users table with id BIGSERIAL PRIMARY KEY and a plain email TEXT NOT NULL column will happily accept two users with the same email. The surrogate key only guarantees that rows are distinct — it does not enforce that the natural values are unique. The fix is to always pair the surrogate PK with explicit UNIQUE constraints on every column that should be a candidate key. Without them, your schema has integrity holes you will find the hard way when a support ticket says "I can't log in, it says there are two accounts with my email".
4. Using VARCHAR natural keys as join columns in high-traffic tables.
Even when the natural key is stable enough to use, a wide string as the join key blows up index sizes, hurts cache hit rates, and bloats every dependent table. A 13-character ISBN in a foreign key is 13 bytes per row; a BIGINT surrogate is 8 bytes per row. Across hundreds of millions of rows and a dozen joins, that difference is measured in gigabytes of RAM and milliseconds of query latency. Unless the table is tiny or the natural key is already numeric, default to a compact surrogate.
5. Exposing the surrogate bigserial in public URLs.
A surrogate key solves stability, but a sequential integer in a URL leaks your record count and enables enumeration attacks (/invoices/1, /invoices/2, ...). The fix depends on the threat model: for internal APIs, bigserial is fine; for public APIs, use UUID v4 or v7 as the external identifier (with a separate internal bigserial if you want compact joins). The public ID is still a surrogate — just a non-guessable one.
Interview Questions
1. "Explain the natural vs surrogate key debate. Which side do you default to and why?"
The debate is whether a primary key should be a meaningful real-world value (natural) or a meaningless database-generated value (surrogate). Proponents of natural keys argue that they are self-documenting, save a column, and already exist outside the database. Proponents of surrogate keys argue that real-world values change more often than people admit, that wide natural keys bloat indexes and foreign keys, and that sensitive natural values (SSN, email) leak into URLs and logs when used as PKs. In practice I default strongly to surrogate keys for almost every table — BIGSERIAL or UUID as the PK, with the natural values enforced as alternate keys via UNIQUE constraints. This gives me stability (nothing outside the database can invalidate the PK), performance (8-byte integer joins), safety (sensitive values never become join keys), and it still preserves the uniqueness guarantee on the real-world columns. The exceptions are narrow: small, immutable reference tables (ISO country codes, currency codes) and pure junction tables where the composite of two foreign keys is the natural PK. Everywhere else, surrogate wins — not because natural keys are wrong in theory, but because the real world is messier than schemas anticipate, and the cost of being wrong is a weekend-long migration.
2. "What is an alternate key and how does it relate to a candidate key?"
A candidate key is any column or set of columns that uniquely identifies rows and cannot be reduced further without losing uniqueness (from Lesson 2.3). A table can have multiple candidate keys — for example a users table might have id, email, and username all as candidate keys. You pick exactly one candidate key to be the primary key, typically the surrogate id. Every other candidate key becomes an alternate key and is enforced with a UNIQUE constraint. Alternate keys are first-class — they still guarantee uniqueness, they are automatically indexed, they can be used as foreign-key targets, and they are the right way to look up rows by values humans actually know (email, slug). The only thing an alternate key lacks compared to the primary key is the semantic "this is the canonical row identifier" role.
3. "Give a concrete example where a natural key is defensible and one where it is not."
Defensible: a countries reference table with code CHAR(2) PRIMARY KEY holding ISO 3166-1 alpha-2 codes ('US', 'GB', 'JP'). The values are assigned by an external authority, globally unique, immutable (countries don't change codes often), compact, and non-sensitive. Foreign keys from other tables pointing at countries.code are readable in raw queries — WHERE country_code = 'US' is self-documenting and needs no join. Not defensible: a users table with email VARCHAR(255) PRIMARY KEY. Email is user-controlled, changes frequently (job changes, marriage, typo fixes), is sensitive enough to appear in privacy regulations, is wide enough to bloat every foreign key, and leaks into URLs and logs the moment it becomes a PK. The right move is id BIGSERIAL PRIMARY KEY with email TEXT NOT NULL UNIQUE as an alternate key — stable PK, uniqueness preserved, and changing an email is a single-row update.
4. "If I use a surrogate key, do I still need a UNIQUE constraint on the natural columns? Why?"
Yes — absolutely. A surrogate key only guarantees that rows are distinct from each other in the eyes of the database; it says nothing about whether the business values in those rows are unique. Without an explicit UNIQUE constraint on email, two rows can have the same email and the database will happily accept them, because the surrogate id already makes them distinct at the PK level. You will only discover the duplicate when a user tries to log in and the query returns two rows. The fix is to always pair a surrogate primary key with UNIQUE constraints on every column or set of columns that represents a real-world candidate key. Conceptually, these UNIQUE constraints are your alternate keys — they re-introduce the uniqueness guarantees that the natural key would have provided if it had been the PK, without the downsides of actually making it the PK.
5. "You are designing a junction table for a many-to-many between users and roles. Do you use a surrogate PK or a composite natural PK? Defend your choice."
For a pure junction table like user_roles(user_id, role_id), I use the composite natural key (user_id, role_id) as the primary key rather than adding a surrogate id. The reasoning: both user_id and role_id are already surrogate keys (they are foreign keys to the surrogate PKs of users and roles), so the composite is small, immutable, and guaranteed unique by the problem itself — you fundamentally cannot have the same user hold the same role twice. Adding a surrogate user_role_id buys nothing: it doesn't improve stability, it adds 8 bytes per row for no benefit, and it actively introduces a bug surface where you could insert two rows with the same (user_id, role_id) unless you also add a UNIQUE constraint (which is exactly the composite key you were trying to avoid). The exception is if the junction table itself becomes a first-class entity — for example enrollments in an LMS that has its own lifecycle, state, and timestamps that other tables reference. At that point it is no longer a pure junction table and a surrogate enrollment_id makes sense. The test: does anything outside this table reference individual rows? If no, composite PK. If yes, surrogate PK plus a UNIQUE on the composite.
Quick Reference — Surrogate vs Natural vs Alternate Key Cheat Sheet
+---------------------------------------------------------------+
| KEY TYPES CHEAT SHEET |
+---------------------------------------------------------------+
| |
| SURROGATE KEY |
| - Generated by the database (BIGSERIAL, UUID, IDENTITY) |
| - No real-world meaning |
| - Immutable, compact, fast to join |
| - Default choice for PK |
| |
| NATURAL KEY |
| - Real-world value (ISBN, email, country code) |
| - Meaningful, self-documenting |
| - Vulnerable to changes in the real world |
| - Use only when value is stable + immutable + non-sensitive |
| |
| ALTERNATE KEY |
| - Candidate key NOT chosen as the PK |
| - Enforced via UNIQUE constraint |
| - Used for lookups by human-known values |
| - Pair EVERY surrogate PK with alternate keys on naturals |
| |
+---------------------------------------------------------------+
+---------------------------------------------------------------+
| DEFAULT PATTERN (MEMORIZE THIS) |
+---------------------------------------------------------------+
| |
| CREATE TABLE <entity> ( |
| id BIGSERIAL PRIMARY KEY, -- surrogate PK |
| <natural> TEXT NOT NULL UNIQUE,-- alternate K |
| <other cols> ... |
| created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() |
| ); |
| |
| RULES: |
| 1. Default to surrogate PK (BIGSERIAL or UUID) |
| 2. Every natural candidate column -> UNIQUE constraint |
| 3. Never use sensitive values (SSN, email) as PK |
| 4. Never use mutable values (name, email) as PK |
| 5. Junction tables -> composite natural PK is fine |
| 6. Reference tables (countries, currencies) -> natural OK |
| 7. Public API IDs -> UUID, not bigserial (no enumeration) |
| 8. Surrogate PK + UNIQUE = stability + integrity |
| |
+---------------------------------------------------------------+
| Concern | Natural Key | Surrogate Key |
|---|---|---|
| Stability | Changes with the real world | Immutable forever |
| Size | Often wide (VARCHAR) | Compact (BIGINT/UUID) |
| Join speed | Slow on wide strings | Fast on integers |
| Leakage risk | High (SSN, email in URLs) | Low (meaningless numbers) |
| Update cost when value changes | Cascades to every FK | Single-row update |
| Self-documenting queries | Yes | No (requires joins) |
| Default for new tables | No | Yes |
| Good fit | Reference + junction tables | Almost everything else |
Prev: Lesson 2.4 -- Composite and Super Key Next: Lesson 3.1 -- Insert Data
This is Lesson 2.5 of the Database Interview Prep Course -- 12 chapters, 58 lessons.