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
SQL
-- 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
);
💡 Tip: Always use DECIMAL for money, never FLOAT! FLOAT stores approximate values — 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
SQL
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
);
💡 Tip: SQLite is lenient with string types — you can actually store strings of any length. However, for code readability and cross-database compatibility, it's still recommended to declare types properly.

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
SQL
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
);
💡 Tip: SQLite has no dedicated date type. Dates are typically stored as 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
SQL
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;
💡 Tip: In SQLite, 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.

SQL
-- 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
💡 Tip: NULL is the biggest pitfall for beginners. Remember two rules: ①Use 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.

SQL
-- 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;
▶ Try it Yourself

Output:

TEXT
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.

SQL
-- 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;
▶ Try it Yourself

Output:

TEXT
id  value  add_result
--  -----  ----------
1   10     110
2   (NULL) (NULL)
3   20     120
SQL
-- 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:

TEXT
id  value  check_result
--  -----  ------------
1   10     Not NULL
2   (NULL) Is NULL
3   20     Not NULL
SQL
-- 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:

TEXT
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:

SQL
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:

SQL
-- 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

Q DECIMAL(10,2) and FLOAT can both store decimals. What's the difference?
A DECIMAL stores exact values, suitable for money and other scenarios where precision is critical. FLOAT stores approximate values, with faster computation but minor errors. Simple rule: Money uses DECIMAL, scientific calculations use FLOAT.
Q How do I choose between CHAR and VARCHAR?
A If data length is fixed (e.g., gender M/F, MD5 hash), CHAR is more efficient. If length varies (e.g., names, titles), VARCHAR saves more space. In practice, VARCHAR is used more often.
Q What's the difference between NULL and an empty string ''?
A NULL means "unknown/no value," while an empty string means "the value is known and it's empty." For example, a "middle name" column: a foreigner might not have a middle name (NULL), while a Chinese person might have one but it's an empty string (''). In aggregate functions, COUNT(column) doesn't count NULL but does count empty strings.
Q How does SQLite's type system differ from other databases?
A SQLite uses a dynamic type system — column type declarations are more like "suggestions" than strict constraints. You can insert a string into an INTEGER column (though not recommended). MySQL, PostgreSQL, and others use strict type systems where type mismatches cause errors. For code portability, use types properly.

📖 Summary


📝 Exercises

Exercise 1 (⭐)

Design a "library borrowing" table with the following fields, choosing appropriate data types:

Exercise 2 (⭐⭐)

Create the table from Exercise 1, insert 5 records, then write queries:

  1. Query all unreturned borrowing records
  2. Query records where notes are NULL
  3. Count all unreturned records (be careful with NULL handling)

Next Lesson

👉 06-practice-basics - Practice: Comprehensive Basic Queries

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏