SQL Data Types Explained
Numeric, string, date and boolean types across the major dialects, and how to pick the type that stops bad data at the door.
- SQL Basics
- DDL
- DML
- SELECT
- WHERE
- Functions
- NULL and Logic
- Aggregate Functions
- GROUP BY
- JOIN
- Subqueries
- Set Operations
- CTEs
- Constraints
- Keys
- Relationships
- Database Design
- Normalisation
- Views
- Window Functions
- Advanced SQL
- Procedures and Functions
- Triggers
- Temporary Tables
- Transactions
- Isolation and Locking
- Indexes
- Query Performance
- SQL Security
- SQL Dialects
- Practical SQL
Concept
A column type is a constraint you get for free. It decides what can be stored, how values sort, how much space a row uses and which functions apply. Choosing types carelessly is the cheapest way to create years of data cleaning work.
Numeric types
| Type | Use for | Notes |
|---|---|---|
SMALLINT, INT, BIGINT | Counts, ids, quantities | Exact. INT stops near 2.1 billion; ids on busy tables want BIGINT. |
DECIMAL(p,s) / NUMERIC(p,s) | Money, rates, anything audited | Exact to the declared scale. DECIMAL(10,2) holds up to 99,999,999.99. |
FLOAT, REAL, DOUBLE | Scientific measurements | Approximate. Never use for money. |
String types
| Type | Use for | Notes |
|---|---|---|
CHAR(n) | Fixed width codes | Padded to n. Good for a 2 letter country code, bad for names. |
VARCHAR(n) | Almost all text | Variable length up to n. |
TEXT / CLOB | Long free text | Often excluded from indexes and some comparisons. |
Date, time and boolean
| Type | Holds |
|---|---|
DATE | Calendar date, no time |
TIME | Time of day |
TIMESTAMP / DATETIME | Date and time; TIMESTAMP WITH TIME ZONE where offsets matter |
BOOLEAN | True or false. MySQL stores it as TINYINT(1); SQL Server has no BOOLEAN and uses BIT. |
Syntax
CREATE TABLE orders (
id BIGINT NOT NULL,
customer_id INT NOT NULL,
order_date DATE NOT NULL,
placed_at TIMESTAMP NOT NULL,
status VARCHAR(12) NOT NULL,
total DECIMAL(10,2) NOT NULL,
is_gift BOOLEAN NOT NULL DEFAULT FALSE,
note TEXT NULL
);Example
Why approximate types are wrong for money:
-- Exact
SELECT CAST(0.1 AS DECIMAL(10,2)) + CAST(0.2 AS DECIMAL(10,2)) AS exact_sum;
-- 0.30
-- Approximate, in every language that uses binary floating point
SELECT 0.1E0 + 0.2E0 AS float_sum;
-- 0.30000000000000004Explanation
DECIMAL stores digits, so 0.1 is exactly 0.1. FLOAT stores a binary approximation, and the tiny error compounds across a million invoice lines until a reconciliation report is off by a few paise. Storage is cheap; a failed audit is not.
Important rules
- Use
DECIMALfor money, always. - Store dates in date types, never as strings.
'31/01/2024'sorts before'01/02/2023'as text. - Size
VARCHARto a real business limit, not to the biggest number you can imagine. - Store timestamps in UTC and convert at the edge, unless the business genuinely needs local wall clock time.
Common mistakes
VARCHARfor phone numbers is correct;INTfor phone numbers is not - leading zeros and plus signs disappear.- Using
FLOATfor prices and then chasing rounding differences. - Declaring everything
VARCHAR(255)out of habit. - Mixing
DATETIMEandTIMESTAMPin MySQL without knowing that onlyTIMESTAMPconverts by session time zone.
Best practices
- Pick the narrowest type that comfortably fits the domain, then leave headroom on ids.
- Keep the same type for the same concept across tables, so joins never need a cast.
- Prefer
CHECKconstraints or lookup tables to a free text status column.
Practice
- Choose a type for each: invoice total, ISO country code, product description, order placed instant, number of items in stock, flag for subscribed to newsletter.
- Explain why
employees.dept_idanddepartments.idshould share a type. - What breaks if a birth date is stored as
VARCHAR(10)? Name two queries that become hard.