Data Types
Data Types
Like storage boxes come in different sizes — small compartments for earrings, medium ones for watches, large ones for scarves — each column in a database also needs the right "box" to store data. Choose the right type, and your data is both safe and space-efficient; choose wrong, and you either waste storage or lose precision.
1. Core Concepts
| Concept | Description |
|---|---|
| Numeric types | Store integers and decimals, including INT, BIGINT, DECIMAL, FLOAT, etc. |
| String types | Store text data, including CHAR, VARCHAR, TEXT |
| Date types | Store dates and times, including DATE, DATETIME, TIMESTAMP |
| Boolean types | Store true/false values; SQLite uses INTEGER (0/1) |
| NULL | Represents "unknown" or "missing" — not an empty string, not zero |
| Type selection principle | Choose the most appropriate type based on data range, precision requirements, and storage efficiency |
2. Basic Syntax
Numeric Types
| Type | Description | Range/Precision | Best For |
|---|---|---|---|
INTEGER / INT |
Integer | ±2.1 billion | IDs, quantities, ages |
BIGINT |
Large integer | ±9.2×10¹⁸ | IDs for massive data, file sizes |
DECIMAL(p,s) / NUMERIC(p,s) |
Exact decimal | p = total digits, s = decimal places | Money, prices (no precision loss) |
FLOAT / REAL |
Floating point | ~7 significant digits | Scientific calculations, approximations |
DOUBLE |
Double precision float | ~15 significant digits | High-precision approximate calculations |
-- DECIMAL for precise money storage
CREATE TABLE accounts (
id INTEGER PRIMARY KEY,
balance DECIMAL(12, 2) -- Up to 12 digits, 2 decimal places
);
-- FLOAT for approximate storage
CREATE TABLE measurements (
id INTEGER PRIMARY KEY,
temperature REAL -- Approximate value, may have minor errors
);
0.1 + 0.2 might equal 0.30000000000000004, which is a disaster in financial scenarios.
String Types
| Type | Description | Max Length | Best For |
|---|---|---|---|
CHAR(n) |
Fixed-length string | 255 bytes | Fixed-length data (e.g., gender M/F, status codes) |
VARCHAR(n) |
Variable-length string | 65535 bytes | Names, emails, titles |
TEXT |
Long text | Unlimited | Article content, notes, descriptions |
CREATE TABLE articles (
id INTEGER PRIMARY KEY,
title VARCHAR(200), -- Title, max 200 characters
status CHAR(1), -- Status: D=Draft, P=Published
content TEXT -- Body, unlimited length
);
Date Types
| Type | Description | Format | Best For |
|---|---|---|---|
DATE |
Date | YYYY-MM-DD |
Birthdays, hire dates |
DATETIME |
Date and time | YYYY-MM-DD HH:MM:SS |
Creation times, appointment times |
TIMESTAMP |
Timestamp | Auto-managed | Record modification times, cross-timezone scenarios |
CREATE TABLE events (
id INTEGER PRIMARY KEY,
event_name TEXT,
event_date DATE, -- Only care about the date
created_at DATETIME DEFAULT CURRENT_TIMESTAMP -- Auto-record creation time
);
TEXT (ISO 8601 format like '2024-01-15') or INTEGER (Unix timestamp). SQLite's built-in date functions (like DATE(), DATETIME()) can correctly handle these formats.
Boolean Types
| Type | Description | Storage Method |
|---|---|---|
BOOLEAN |
True/False | Stored as INTEGER in SQLite: 0=false, 1=true |
BIT |
Bit value | Used in MySQL/SQL Server |
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT,
is_active BOOLEAN DEFAULT 1 -- 1=enabled, 0=disabled
);
-- Insert boolean values
INSERT INTO users (name, is_active) VALUES ('John', TRUE); -- Stored as 1
INSERT INTO users (name, is_active) VALUES ('Jane', FALSE); -- Stored as 0
-- Query using boolean values
SELECT * FROM users WHERE is_active = 1;
TRUE equals 1 and FALSE equals 0. But for code readability, it's recommended to use TRUE/FALSE instead of writing numbers directly.
The Meaning of NULL
NULL represents "unknown" or "missing" — it is not an empty string '', not the number 0, and certainly not FALSE.
-- Any operation involving NULL results in NULL
SELECT NULL + 1; -- Result: NULL
SELECT NULL || 'hello'; -- Result: NULL
-- To check for NULL, you must use IS / IS NOT
SELECT * FROM employees WHERE department_id IS NULL; -- ✅ Correct
SELECT * FROM employees WHERE department_id = NULL; -- ❌ Always returns empty
SELECT * FROM employees WHERE department_id IS NOT NULL; -- ✅ Correct
IS to check for NULL, not =; ②Any operation involving NULL results in NULL.
Type Selection Best Practices
| Scenario | Recommended Type | Reason |
|---|---|---|
| Primary key ID | INTEGER PRIMARY KEY AUTOINCREMENT |
Integers are faster than strings; auto-increment is convenient |
| Money/Prices | DECIMAL(10,2) |
Precise storage, no rounding errors |
| Usernames/Titles | VARCHAR(100) |
Variable-length saves space; length limit prevents abuse |
| Article body | TEXT |
Unlimited length, suitable for large text |
| Dates | DATE / DATETIME |
Clear semantics, built-in date function support |
| Yes/No flags | BOOLEAN |
Clear semantics, compact storage |
| Enum status | CHAR(1) or INTEGER |
More flexible than ENUM type |
3. Code Examples
Example: Create a Products Table and Verify Type Constraints (Difficulty ⭐)
Create a products table to experience the behavior of different data types.
-- Create products table with specified column types
CREATE TABLE products_demo (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
stock INTEGER DEFAULT 0,
description TEXT,
is_active BOOLEAN DEFAULT 1,
created_at DATE
);
-- Insert data of various types
INSERT INTO products_demo (name, price, stock, description, is_active, created_at)
VALUES ('Mechanical Keyboard', 299.50, 100, 'Blue switch 87-key mechanical keyboard, great for typing', TRUE, '2024-01-15');
INSERT INTO products_demo (name, price, stock, description, is_active, created_at)
VALUES ('Wireless Mouse', 89.00, 200, NULL, TRUE, '2024-02-20');
-- View data and type behavior
SELECT name, price, stock, description, is_active, created_at
FROM products_demo;
Output:
name price stock description is_active created_at
---------------- ------- ----- --------------------------------------------- --------- ----------
Mechanical Keyboard 299.50 100 Blue switch 87-key mechanical keyboard... 1 2024-01-15
Wireless Mouse 89.00 200 (NULL) 1 2024-02-20
Example: Verify NULL's Arithmetic Properties (Difficulty ⭐⭐)
Understand NULL's special behavior through actual queries.
-- Create test table
CREATE TABLE null_test (
id INTEGER PRIMARY KEY,
value INTEGER
);
INSERT INTO null_test VALUES (1, 10);
INSERT INTO null_test VALUES (2, NULL);
INSERT INTO null_test VALUES (3, 20);
-- NULL in arithmetic operations
SELECT id, value, value + 100 AS add_result
FROM null_test;
Output:
id value add_result
-- ----- ----------
1 10 110
2 (NULL) (NULL)
3 20 120
-- Checking for NULL: IS vs =
SELECT id, value,
CASE WHEN value IS NULL THEN 'Is NULL' ELSE 'Not NULL' END AS check_result
FROM null_test;
Output:
id value check_result
-- ----- ------------
1 10 Not NULL
2 (NULL) Is NULL
3 20 Not NULL
-- NULL and aggregate functions: COUNT excludes NULL, SUM/AVG ignore NULL
SELECT COUNT(value) AS count_val, -- 2 (doesn't count NULL)
COUNT(*) AS count_all, -- 3 (counts all rows)
SUM(value) AS sum_val, -- 30 (ignores NULL)
AVG(value) AS avg_val -- 15 (30/2, not 30/3)
FROM null_test;
Output:
count_val count_all sum_val avg_val
--------- --------- ------- -------
2 3 30 15.0
4. Common Application Scenarios
Scenario 1: Design a User Registration Table
Choose appropriate types based on business requirements:
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username VARCHAR(50) NOT NULL UNIQUE, -- Username, unique and not null
email VARCHAR(100) NOT NULL UNIQUE, -- Email
password_hash CHAR(64) NOT NULL, -- SHA256 hash, fixed 64 characters
age INTEGER CHECK (age >= 0 AND age <= 150), -- Age, reasonable range check
balance DECIMAL(12, 2) DEFAULT 0.00, -- Account balance, precise to the cent
bio TEXT, -- Bio, unlimited length
is_verified BOOLEAN DEFAULT 0, -- Whether email is verified
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
Scenario 2: Handling NULL with Default Values
Use the COALESCE function to provide default values for NULL:
-- Query employee info, show "Unassigned" when department is NULL
SELECT e.name,
COALESCE(d.name, 'Unassigned') AS department,
COALESCE(e.salary, 0) AS salary
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id;
❓ FAQ
📖 Summary
- Numeric types: Use INT/BIGINT for integers, DECIMAL for exact decimals (must use for money), FLOAT for approximate values
- String types: Use CHAR for fixed length, VARCHAR for variable length, TEXT for large text
- Date types: DATE stores dates, DATETIME stores dates with time, TIMESTAMP auto-manages
- Boolean types: BOOLEAN stores TRUE/FALSE; in SQLite it's actually INTEGER 0/1
- NULL means "unknown"; check with
IS NULLnot= NULL; operations involving NULL still result in NULL - Type selection principle: Consider data range, precision requirements, and storage efficiency; always use DECIMAL for money
📝 Exercises
Exercise 1 (⭐)
Design a "library borrowing" table with the following fields, choosing appropriate data types:
- Borrowing ID (primary key)
- Book title (max 200 characters)
- ISBN (fixed 13 characters)
- Borrower name
- Borrow date
- Due date
- Whether returned
- Notes (nullable)
Exercise 2 (⭐⭐)
Create the table from Exercise 1, insert 5 records, then write queries:
- Query all unreturned borrowing records
- Query records where notes are NULL
- Count all unreturned records (be careful with NULL handling)
Next Lesson
👉 06-practice-basics - Practice: Comprehensive Basic Queries



