Data types and NULL: what a column is allowed to hold
Why databases force every column to have a fixed type, and the surprisingly tricky logic of "missing" data.
10 min readUpdated 2026-09-04databasesdata-typesfundamentals
Sorting mail into the right slot
Imagine a post office with pigeonholes labeled "letters," "postcards," and "packages." If someone tries to shove a package into the letters slot, it simply won't fit — the slot is shaped for something smaller. That physical constraint prevents a whole category of mistakes before they can even happen.
A column's data type is exactly this: a fixed shape that every value in that column must fit. If a column is declaredINTEGER, the database physically will not let the text "banana" in — it rejects the insert outright. This is the database enforcing correctness before bad data ever gets stored, rather than your application having to check everything by hand, every time, everywhere it touches the data.
The core data types, and why each one exists
Every relational database has its own exact list of type names, but they all boil down to the same handful of ideas:
| Category | Common names | What it holds | Why it's separate from the others |
|---|---|---|---|
| Integer | INTEGER, INT, BIGINT, SMALLINT | Whole numbers | Stored as raw binary numbers — fast math, but no decimals, and a fixed maximum size |
| Decimal / numeric | DECIMAL(p,s), NUMERIC | Exact decimal numbers (money!) | Stores digits exactly, unlike floating point (see math section below) |
| Floating point | REAL, FLOAT, DOUBLE | Approximate decimal numbers | Faster and more compact, but can't represent every decimal exactly |
| Text | VARCHAR(n), TEXT, CHAR(n) | Strings | VARCHAR(n) caps length at n; TEXT is unbounded; CHAR(n) pads to a fixed width |
| Boolean | BOOLEAN | true / false | Some databases (older MySQL) fake this with TINYINT(1) |
| Date/time | DATE, TIME, TIMESTAMP | Calendar dates and clock times | Lets the database do date arithmetic (+ INTERVAL '1 day') correctly, including leap years |
| Binary | BLOB, BYTEA | Raw bytes (images, files) | Not meant to be interpreted as text at all |
| JSON | JSON, JSONB | Semi-structured nested data | A relational database's escape hatch for data that doesn't fit neatly into columns — more in the PostgreSQL module |
sql
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
in_stock BOOLEAN DEFAULT TRUE,
added_on DATE DEFAULT CURRENT_DATE
);
The math you must never skip: why money uses DECIMAL, not FLOAT
This is one of the most common real-world bugs in all of software, and it comes directly from how computers represent numbers in binary.
Floating-point numbers (FLOAT, DOUBLE) store values in binary fractions — powers of (like ) added together. The problem: many ordinary decimal fractions, like , cannot be represented exactly in binary, the same way cannot be written exactly in decimal (it's forever).
Concretely, if you add using floating point, you do not get exactly :
For a game's physics engine, that tiny error is irrelevant. For a bank account, it is a genuine bug — multiply small errors across millions of transactions and real money goes missing or appears from nowhere.
DECIMAL(p, s) avoids this entirely by storing numbers as exact digit sequences instead of binary fractions: p (precision) is the total number of digits, and s (scale) is how many of those sit after the decimal point. DECIMAL(10, 2) stores up to 10 total digits, 2 after the point — exactly representing 12345678.90, with zero rounding error, forever.
Rule of thumb used throughout the industry: if a number will ever be added, subtracted, or compared for exact equality — money, quantities, measurements that must reconcile — use DECIMAL/NUMERIC. Use FLOAT/DOUBLE only for values where tiny imprecision is acceptable, like a sensor reading or a machine-learning score.
NULL: the value that means "nothing here"
Every column type above describes what a known value looks like. But what if a value is simply unknown or doesn't apply? A student who hasn't taken an exam yet doesn't have a score of0 — zero is a real, wrong answer. They have no score. SQL represents this with a special marker: NULL.
NULL is not zero, not an empty string, and not false. It specifically means "unknown" or "not applicable." This sounds simple but has a genuinely tricky consequence: any comparison against NULL returns neither true nor false — it returns "unknown."
sql
SELECT * FROM students WHERE marks = NULL; -- returns ZERO rows, always
SELECT * FROM students WHERE marks IS NULL; -- this is the correct way to check
marks = NULL never matches anything, even rows where marks genuinely is NULL — because "is this unknown value equal to this other unknown thing?" is itself unknown, and SQL only returns rows where a condition evaluates to true (not "unknown"). This is called three-valued logic: every condition in SQL evaluates to TRUE, FALSE, or UNKNOWN, and only TRUE rows survive a WHERE clause.
Notice F AND U = F (a false short-circuits, regardless of the unknown), but T AND U = U (unknown survives when nothing forces it either way). This is exactly how a real database engine evaluates every multi-condition WHERE clause — worth internalizing now, because forgetting it causes real, hard-to-spot bugs later (see below).
Try it: NULL behaves unlike any real valuesql
Loading editor…
Common mistakes
- Writing
WHERE column = NULL. As shown above, this silently matches nothing, ever. Always useIS NULL/IS NOT NULL. - Using
FLOATfor currency. Leads to values like19.999999999998appearing after enough arithmetic. UseDECIMAL. - Forgetting
NOT NULLwhere it matters. By default, most columns allowNULLunless you say otherwise. Anamecolumn with noNOT NULLconstraint will happily accept a row with no name at all — decide deliberately whether that's acceptable. - Assuming
NOT INworks intuitively withNULL.WHERE id NOT IN (1, 2, NULL)returns zero rows, for every single row, because comparing against theNULLin that list makes the whole conditionUNKNOWN. This trips up experienced engineers, not just beginners.
Summary
Data types are the database enforcing "this column can only ever hold this shape of value," catching bad data at the door rather than downstream.DECIMAL and FLOAT look similar but solve different problems — exactness versus compactness — and picking wrong for money is one of the most common real bugs in software. NULL means "unknown," not zero or empty, and SQL's three-valued logic (TRUE/FALSE/UNKNOWN) means comparisons against NULL never behave like ordinary comparisons — you must use IS NULL. With the shape of a single table now solid, the last lesson in this module gets your hands on a real, running database so the next module's SQL isn't just theory.