CMD Guide
HomeDatabasesSQL Fundamentals

Keys in SQL

A key is a uniqueness promise that the engine physically enforces: when you declare one, the database builds a unique index over those columns, and every INSERT/UPDATE probes that index before committing the row — so the cost of a key is not just "no duplicates," it is a B-tree the engine must keep sorted and search on every write. Everything else (primary, foreign, composite, candidate) is a role layered on top of that one mechanism.

The hierarchy: superkey → candidate → primary

The taxonomy comes from functional dependency, not from syntax. Start with a real employee instance and ask which column-sets can identify a row.

idemailssndept_idname
1ava@co.com111-22-333310Ava
2ben@co.com444-55-666610Ben
3cole@co.com777-88-999920Cole

So every primary key is a candidate key is a superkey — but not the reverse. The grader's note flagged this missing layer: "candidate key" only means something relative to "superkey."

diagram
diagram

DDL: declaring each key (and what the engine does)

Correct, compilable DDL. A composite primary key, two alternate keys, and a foreign key with an explicit referential action.

-- Parent table
CREATE TABLE department (
    dept_id   INT PRIMARY KEY,
    name      VARCHAR(60) NOT NULL
);

-- Child table
CREATE TABLE employee (
    id        INT GENERATED ALWAYS AS IDENTITY,  -- surrogate PK
    email     VARCHAR(120) NOT NULL,
    ssn       CHAR(11),
    dept_id   INT NOT NULL,

    CONSTRAINT pk_employee  PRIMARY KEY (id),            -- elected candidate
    CONSTRAINT uq_email     UNIQUE (email),              -- alternate key, NOT NULL here
    CONSTRAINT uq_ssn       UNIQUE (ssn),                -- alternate key, NULLs allowed
    CONSTRAINT fk_dept      FOREIGN KEY (dept_id)
                            REFERENCES department (dept_id)
                            ON DELETE RESTRICT
                            ON UPDATE CASCADE
);

-- Composite (multi-column) key on a junction table:
CREATE TABLE employee_project (
    emp_id     INT REFERENCES employee (id),
    project_id INT,
    role       VARCHAR(40),
    PRIMARY KEY (emp_id, project_id)   -- the PAIR must be unique, not each column
);

What the engine actually creates: PRIMARY KEY builds a unique index and adds an implicit NOT NULL; each UNIQUE builds its own unique index; the FOREIGN KEY creates no index on the child by default — it only validates that dept_id exists in the parent's PK index on each write.

Worked trace: a write touches every key

Run this against the schema above and follow the engine. department holds (10,'Eng') and (20,'Sales'); employee already holds rows 1–3 from the table earlier.

  1. INSERT INTO employee(email, ssn, dept_id) VALUES ('dave@co.com','111-22-3333', 10)
  2. Engine assigns id = 4 from the identity sequence; probes pk_employee index for 4 → absent → OK.
  3. Probes uq_email index for 'dave@co.com' → absent → OK.
  4. Probes uq_ssn index for '111-22-3333'found on row 1 (Ava)violation. The whole statement aborts: ERROR: duplicate key value violates unique constraint "uq_ssn". No partial row is written.
  5. Fix the SSN and retry: ... VALUES ('dave@co.com','000-00-0001', 10). Now the FK fires: probe department PK index for dept_id = 10 → found → OK. Row 4 commits.
  6. Later: DELETE FROM department WHERE dept_id = 10. The ON DELETE RESTRICT action scans for children referencing 10, finds rows 1, 2, 4 → blocks the delete. With ON DELETE CASCADE instead, those three employee rows would be deleted with the parent.

The takeaway from the trace: a single insert did three index probes plus a FK lookup. That is the real cost of a richly-keyed table — and the reason key choice is a performance decision, not just a correctness one.

Referential actions: what happens to children when the parent changes

The ON DELETE / ON UPDATE clause is the part of foreign keys the glossary version omitted, and it is where most production incidents live.

ActionOn parent DELETE / UPDATEUse when
RESTRICT / NO ACTIONReject the operation if any child references the rowDefault, safest: you want to be forced to deal with orphans explicitly
CASCADEDelete/update the child rows tooChild is owned by parent (order → order_items); deleting the order should delete its lines
SET NULLSet the child's FK column to NULL (column must be nullable)Child can outlive parent (employee → manager who quits)
SET DEFAULTSet the FK to its column defaultRare; the default value must itself exist in the parent

NO ACTION vs RESTRICT: both reject, but NO ACTION defers the check to end-of-statement (so within one statement a transient violation can heal), while RESTRICT rejects immediately. In most cases the behaviour is identical.

Pitfalls

Takeaways


Sources: ISO/IEC 9075 (SQL standard) definitions of candidate, primary, and foreign keys; C. J. Date, An Introduction to Database Systems (superkey/candidate-key minimality); Silberschatz, Korth & Sudarshan, Database System Concepts (keys and referential integrity); PostgreSQL 16 docs (CREATE TABLE constraints, NULLS NOT DISTINCT, referential actions); MySQL 8.0 Reference Manual (InnoDB clustered index, foreign-key indexing). Re-authored and deepened for this guide: replaced the definition-only glossary with the superkey→candidate→primary hierarchy, compilable DDL, a traced multi-index write, referential actions, and engine-level pitfalls.

🎯 STRICT STANDOUT: Why / worked / when-not / failure / drills — Keys in SQL

Why this concept exists (judgment chain)

Every key is a uniqueness promise backed by a unique index probed on write. Superkey ⊃ candidate ⊃ primary is FD theory; FK actions and UNIQUE NULL semantics are where production integrity fails.

Worked example with numbers or traced steps

employee candidates: {id}, {email}, {ssn}; elect id as PK; UNIQUE email/ssn.
INSERT duplicate ssn → unique index probe fails; whole statement aborts.
FK ON DELETE RESTRICT blocks DELETE department with children;
CASCADE would delete employees; SET NULL needs nullable FK.
UNIQUE(email) allows many NULL emails (NULL≠NULL) unless NULLS NOT DISTINCT.
Child FK unindexed → CASCADE parent delete sequential-scans child.

When NOT to use / named alternative

Do not use natural email/SSN as PK if values change — surrogate PK + UNIQUE alternate. Do not CASCADE delete from shared lookup tables. Avoid UUID PKs as InnoDB clustered keys without sequential alternative (random insert scatter). Skip redundant UNIQUE that duplicates PK.

Failure / ops fingerprint

Fingerprint: 50 NULL “unique” emails; DELETE parent hangs on 50M child without FK index; cascade wipe of orders. Ops: always CREATE INDEX on FK columns; choose ON DELETE deliberately; monitor constraint violation rates.

Hostile-panel drills (defend the decision)

Q1. Superkey vs candidate vs primary?
Model answer: Superkey = any unique column set; candidate = minimal superkey; primary = elected candidate; others → UNIQUE alternates.

Q2. Does UNIQUE ban multiple NULLs?
Model answer: Standard/PG: no — NULL≠NULL. Use NULLS NOT DISTINCT (PG15+) or partial unique index.

Q3. Cost of one INSERT with PK+2 UNIQUE+FK?
Model answer: Probe each unique index + parent PK for FK — multi-index write path; keys are a performance decision.

🤖 Don't fully get this? Learn it with Claude

Stuck on Keys in SQL? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Keys in SQL** (Databases) and want to truly understand it. Explain Keys in SQL from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Keys in SQL** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Keys in SQL** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Keys in SQL** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes