Data Types in SQL
Understanding SQL data types: numbers, strings, dates, booleans, and NULL values.
Introduction to SQL Data Types
Just like in Python where variables have types (int, str, float), SQL columns have data types that define what kind of data they can store. Choosing the right data type is crucial for:
- Data integrity: Ensuring only valid data is stored
- Storage efficiency: Using the appropriate amount of space
- Query performance: Optimizing how data is indexed and searched
When you create a table, you specify a data type for each column. This tells the database exactly what kind of values that column can hold.
Numeric Data Types
Numeric types store numbers - both whole numbers (integers) and decimal numbers (floating-point).
Type | Description | Range | Storage | Use Case |
|---|---|---|---|---|
| INT | Integer (whole numbers) | -2,147,483,648 to 2,147,483,647 | 4 bytes | IDs, counts, quantities |
| BIGINT | Large integers | ±9 quintillion | 8 bytes | Large IDs, timestamps |
| SMALLINT | Small integers | -32,768 to 32,767 | 2 bytes | Small counts, ages |
| DECIMAL(p,s) | Exact decimal | Varies by precision | Varies | Money, precise calculations |
| FLOAT | Approximate decimal | ~7 decimal digits precision | 4 bytes | Scientific measurements |
| DOUBLE | Large approximate decimal | ~15 decimal digits precision | 8 bytes | Complex calculations |
INT vs BIGINT:
CREATE TABLE products (
product_id INT, -- Regular ID (up to 2 billion)
barcode BIGINT, -- Large numbers (like UPC codes)
stock_quantity SMALLINT -- Small numbers (won't exceed 32k)
);DECIMAL vs FLOAT:
DECIMAL(p, s) stores exact values - perfect for money!
- p = precision (total digits)
- s = scale (digits after decimal)
CREATE TABLE financial (
price DECIMAL(10,2), -- $99,999,999.99 max, EXACT
measurement FLOAT -- Approximate, for science
);
INSERT INTO financial VALUES (19.99, 19.99);
SELECT * FROM financial;Important: Never use FLOAT or DOUBLE for money! They're approximate and can cause rounding errors. Always use DECIMAL for financial data.
String Data Types
String types store text data - from single characters to large blocks of text.
Type | Description | Max Length | Storage | Use Case |
|---|---|---|---|---|
| CHAR(n) | Fixed-length string | n characters | n bytes | Country codes, zip codes |
| VARCHAR(n) | Variable-length string | n characters | Length + 1-2 bytes | Names, emails, titles |
| TEXT | Large text | ~65,535 characters | Length + 2 bytes | Articles, descriptions |
| MEDIUMTEXT | Very large text | ~16 million chars | Length + 3 bytes | Books, large documents |
| LONGTEXT | Huge text | ~4 GB | Length + 4 bytes | Extremely large content |
CHAR vs VARCHAR:
- CHAR(n): Always uses n characters of space (padded with spaces)
- VARCHAR(n): Uses only the space needed (up to n characters)
CREATE TABLE users (
country_code CHAR(2), -- Always 2 chars: 'US', 'UK'
username VARCHAR(50), -- Up to 50 chars
bio TEXT -- Large description
);
INSERT INTO users VALUES ('US', 'alice', 'Software engineer who loves databases');
SELECT * FROM users;Best Practice: Use VARCHAR for most text fields. Only use CHAR when the length is always the same (like country codes or zip codes).
Date and Time Data Types
Date and time types store temporal data - crucial for tracking when things happened.
Type | Description | Format | Range | Use Case |
|---|---|---|---|---|
| DATE | Date only | YYYY-MM-DD | 1000-01-01 to 9999-12-31 | Birthdays, deadlines |
| TIME | Time only | HH:MM:SS | -838:59:59 to 838:59:59 | Business hours, duration |
| DATETIME | Date and time | YYYY-MM-DD HH:MM:SS | 1000-01-01 to 9999-12-31 | Event timestamps |
| TIMESTAMP | Auto-updating timestamp | YYYY-MM-DD HH:MM:SS | 1970-01-01 to 2038-01-19 | Created/updated times |
| YEAR | Year only | YYYY | 1901 to 2155 | Birth year, fiscal year |
CREATE TABLE events (
event_id INT PRIMARY KEY,
event_name VARCHAR(100),
event_date DATE, -- Just the date
event_time TIME, -- Just the time
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Auto-timestamp
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
INSERT INTO events (event_id, event_name, event_date, event_time)
VALUES (1, 'Team Meeting', '2024-06-15', '14:30:00');
SELECT * FROM events;DATETIME vs TIMESTAMP:
- DATETIME: Stores the exact date/time you specify
- TIMESTAMP: Can auto-update to current time, but limited to year 2038
Tip: Use TIMESTAMP with DEFAULT CURRENT_TIMESTAMP for "created_at" columns. It automatically records when the row was inserted!
Boolean Data Type
Boolean types store TRUE or FALSE values.
Stores logical true/false values. In MySQL, BOOLEAN is actually stored as TINYINT(1) where 0 = FALSE and 1 = TRUE.
CREATE TABLE products (
product_id INT PRIMARY KEY,
product_name VARCHAR(100),
in_stock BOOLEAN, -- TRUE or FALSE
is_featured BOOL, -- Same as BOOLEAN
is_on_sale TINYINT(1) -- 0 or 1
);
INSERT INTO products VALUES
(1, 'Laptop', TRUE, FALSE, 1),
(2, 'Mouse', 1, 0, FALSE); -- You can use TRUE/FALSE or 1/0
SELECT * FROM products;You can query boolean columns naturally:
SELECT product_name, in_stock
FROM products
WHERE in_stock = TRUE;NULL Values
NULL is a special value that represents "no value" or "unknown". It's different from zero or an empty string!
NULL means the absence of a value. It's not zero, not an empty string, and not false - it's "unknown" or "not applicable."
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL, -- Cannot be NULL
email VARCHAR(100), -- Can be NULL
salary DECIMAL(10,2) NOT NULL, -- Cannot be NULL
manager_id INT -- Can be NULL (CEO has no manager)
);
INSERT INTO employees (id, name, email, salary, manager_id)
VALUES
(1, 'Alice', 'alice@company.com', 75000, NULL), -- No manager (CEO)
(2, 'Bob', NULL, 65000, 1); -- No email provided
SELECT * FROM employees;Important: NULL is not equal to anything, not even NULL! Use IS NULL or IS NOT NULL to check for NULL values, not = NULL.
Choosing the Right Data Type
Here's a practical guide for choosing data types:
If you're storing... | Use this type | Example |
|---|---|---|
| User IDs, Order IDs | INT or BIGINT | `user_id INT PRIMARY KEY` |
| Names, Titles | VARCHAR(n) | `name VARCHAR(100)` |
| Email addresses | VARCHAR(255) | `email VARCHAR(255)` |
| Prices, Money | DECIMAL(10,2) | `price DECIMAL(10,2)` |
| Product descriptions | TEXT | `description TEXT` |
| Birth dates | DATE | `birth_date DATE` |
| Login timestamps | TIMESTAMP | `last_login TIMESTAMP` |
| Account status | BOOLEAN | `is_active BOOLEAN` |
| Phone numbers | VARCHAR(20) | `phone VARCHAR(20)` |
| Zip/Postal codes | VARCHAR(10) | `zip_code VARCHAR(10)` |
| Country codes | CHAR(2) | `country CHAR(2)` |
Complete Example
Let's create a realistic table with various data types:
CREATE TABLE customers (
-- Primary key
customer_id INT PRIMARY KEY AUTO_INCREMENT,
-- String types
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
phone VARCHAR(20),
-- Numeric types
age SMALLINT,
account_balance DECIMAL(12,2) DEFAULT 0.00,
-- Boolean types
is_active BOOLEAN DEFAULT TRUE,
email_verified BOOLEAN DEFAULT FALSE,
-- Date/Time types
birth_date DATE,
registered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP NULL,
-- Text types
address TEXT,
notes TEXT
);INSERT INTO customers
(first_name, last_name, email, phone, age, birth_date)
VALUES
('Alice', 'Johnson', 'alice@email.com', '555-1234', 30, '1994-03-15'),
('Bob', 'Smith', 'bob@email.com', NULL, 28, '1996-07-22');
SELECT customer_id, first_name, last_name, email, age, is_active
FROM customers;Common Mistakes to Avoid
Don't make these mistakes:
- Using VARCHAR without a length: Always specify
VARCHAR(100), not justVARCHAR - Using FLOAT for money: Use
DECIMAL(10,2)instead - Storing phone numbers as INT: Use
VARCHAR(20)to preserve formatting and leading zeros - Forgetting NOT NULL: Add
NOT NULLto required fields - Using huge VARCHAR sizes:
VARCHAR(1000)when you only need 50 wastes resources