4.4.1 · D2Databases

Visual walkthrough — Relational model — tables, rows, columns, NULL

2,371 words11 min readBack to topic

We assume you have never seen a database. Line one starts from a blank board.


Step 1 — A single fact is a labelled box

WHY start here. Everything in a database — the whole grid — is just many of these boxes tiled together. If we understand one box, the grid is only bookkeeping. We must never draw the grid before we have earned the box.

PICTURE. Look at the figure: the word above the line is the column name (also called an attribute) — it tells you what kind of fact this is. The value below the line is the actual data. The name is fixed forever; the value changes from record to record.

Figure — Relational model — tables, rows, columns, NULL

Step 2 — Snap boxes side by side → a row

WHY snap them together. A single box ("age = 20") floats free — 20 of what? Lining the boxes up under shared column names ties the values to one subject. The row is the smallest unit that is a complete fact about one entity.

PICTURE. The four boxes id | name | age | major sit in a row. Read across left to right and you get one full sentence: "Student #1, named Asha, age 20, studies CS." The column names sit on top as a shared header; the values sit underneath.

Figure — Relational model — tables, rows, columns, NULL

Step 3 — Stack rows under one header → a table

WHY write the header once. Every row answers the same questions in the same order. Repeating the column names per row would be wasteful and error-prone, so we lift them out into a single header. The header + column domains is called the schema — the shape of the table, separate from the data filling it.

PICTURE. The shared header id · name · age · major runs across the top in chalk blue. Three rows hang below it. Count the columns going across — that count is the degree. Count the rows going down — that count is the cardinality.

Figure — Relational model — tables, rows, columns, NULL

Every column has a domain — the set of values it is allowed to hold (e.g. age may only hold integers). The schema pins that down.


Step 4 — A box left empty: introducing NULL

WHY a special marker, not 0. Writing 0 would be a lie: it claims "Ravi is zero years old." Writing '' (empty text) is also a claim — "his age is the empty string." NULL claims nothing at all. It is the honest symbol for "no clue."

PICTURE. In the figure, Ravi's age box and Mira's major box are hatched over with a pale-yellow "?" — they are placeholders for the absent. Compare them with a genuine 0 drawn nearby: the 0 box is solid; the NULL box is see-through. Same screen-emptiness, completely different meaning.

Figure — Relational model — tables, rows, columns, NULL

Step 5 — Why NULL forces a THIRD truth value

WHY not just guess TRUE or FALSE. Ordinary logic is two-valued — every statement is TRUE or FALSE. But a question about an unknown quantity has no honest yes/no answer. Forcing one would make the database lie. The clean fix is to admit a third outcome. This is called three-valued logic (3VL).

PICTURE. On the left, a normal number line: pick 21, and any known age lands clearly left (FALSE) or right (TRUE). On the right, Ravi's age is a fog cloud sitting across the 21 mark — it might be left, might be right. The arrow can't commit. That fog is UNKNOWN.

Figure — Relational model — tables, rows, columns, NULL

Step 6 — Deriving the AND / OR rules from "U = could be either"

WHY this trick works. We don't need new rules pulled from thin air — we derive 3VL from the two-valued rules we already trust, by testing both hidden values. This is the honest bookkeeping of ignorance.

PICTURE. The figure runs the two experiments as branching chalk arrows:

  • TRUE AND U: if U=TRUE → TRUE; if U=FALSE → FALSE. The two branches disagree → collapse to U.
  • FALSE AND U: AND needs both TRUE; one side is already FALSE → both branches say FALSE → answer FALSE.
  • TRUE OR U: OR needs one TRUE; one side is already TRUE → both branches say TRUE → answer TRUE.
  • FALSE OR U: if U=TRUE → TRUE; if U=FALSE → FALSE. Branches disagreeU.
Figure — Relational model — tables, rows, columns, NULL

Step 7 — WHERE is a filter that only lets TRUE through

WHY UNKNOWN is dropped, not kept. The gate's job is to admit rows we are sure satisfy the condition. "Maybe" is not "sure." So U fails the gate exactly like FALSE does. This single design choice causes the famous NULL "disappearances."

PICTURE. Three rows flow toward the WHERE gate. Asha's condition is TRUE (green) → passes. A hypothetical FALSE row is blocked. Ravi's condition is U (yellow fog) → also blocked. Only the green TRUE row lands in the result.

Figure — Relational model — tables, rows, columns, NULL

Step 8 — The classic gotcha, fully derived

WHY he vanishes. Ravi's age is NULL, so both halves of the OR touch NULL:

Then Step 7's gate throws out the U row. Ravi is gone.

PICTURE. The figure traces Ravi's row through both sub-conditions (both fog), the OR (still fog), and the WHERE gate (blocked). Alongside, the fix: add OR age IS NULL. The operator IS NULL is special — it asks "is this box the NULL marker?" and returns a real TRUE/FALSE, never U. That TRUE opens the gate.

Figure — Relational model — tables, rows, columns, NULL

Need a value instead of a survival test? Use COALESCE: COALESCE(age, 0) hands back age if known, else 0.


Edge cases — the degenerate tables


The one-picture summary

Below, the entire chain in a single frame: box → row → table (structure), then empty box → NULL → UNKNOWN → 3VL rules → WHERE gate → who survives (logic). Trace it top to bottom and you have re-derived the parent note without memorising a thing.

Figure — Relational model — tables, rows, columns, NULL
Recall Feynman retelling — say it to a friend

Start with one labelled box: a word on top (what kind of fact), a value inside. Snap four boxes in a line and you've described one student completely — that's a row. Write the four labels once at the top and stack many rows below — that's a table; count across for degree, count down for cardinality. Now suppose one box is empty because we never learned the value — we drop in NULL, meaning no clue, not zero. The trouble: if you ask "is this unknown age over 21?", there's no honest yes or no, so the computer invents a third answer, UNKNOWN. Pretend UNKNOWN is secretly true-or-false and test both ways: AND dies the moment it meets a FALSE, OR wins the moment it meets a TRUE, and everything else stays foggy. Finally, WHERE is a gate that only lets TRUE through — so foggy rows quietly disappear. That's why age = 20 OR age <> 20 still loses Ravi, and why IS NULL (which gives a real TRUE) is the rescue.

Recall Rapid self-test

Degree of a 5-column, 40-row table? ::: 5 Cardinality of that table? ::: 40 FALSE AND NULL = ? ::: FALSE (AND fears FALSE) TRUE OR NULL = ? ::: TRUE (OR loves TRUE) NULL = NULL = ? ::: UNKNOWN Does a U row pass WHERE? ::: No — only TRUE passes What does COUNT(col) do with NULLs? ::: Skips them Rescue operator for missing values in a test? ::: IS NULL


Connections

  • Parent topic
  • SQL SELECT and WHERE — the gate from Step 7 in real syntax
  • COALESCE and NULL handling functions — turning NULL into a usable value
  • Primary Keys and Uniqueness — forbidding the duplicate rows of the edge case
  • Data Types and Domains — what each column box may hold
  • Foreign Keys and Referential Integrity · Normalization