SQLite is a lightweight, self-contained SQL database engine known for its simplicity and versatility. In version 3.37.0, SQLite introduced strict tables, offering stricter type enforcement compared to its regular tables.
This feature allows developers to define tables with precise data types, ensuring better data consistency.
In this article, we’ll look at the six supported data types for strict tables—INT
, INTEGER
, REAL
, TEXT
, BLOB
, and ANY
—and provide simple examples to illustrate their usage.
Overview of Strict Tables
SQLite traditionally uses a dynamic type system known as type affinity, where values can deviate from their declared column type. This is where you can insert a value that doesn’t adhere to the declared column type, and SQLite will accept it without a problem.
Strict tables, on the other hand, enforce type constraints rigorously. This ensures that the data matches the declared type, which enhances data integrity and predictability.
When defining a strict table, you must include the STRICT
keyword in the table definition. For example:
CREATE TABLE example_table (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
age INT,
data BLOB
) STRICT;
The STRICT
keyword follows the end parenthesis of the table definition.
Strict tables allow the following explicit data types:
INT
INTEGER
REAL
TEXT
BLOB
ANY
Let’s explore each in detail.
INT
INT
is used to store small or large whole numbers without fractional components. It is typically used for fields like counters, IDs, or attributes requiring integer values.
Characteristics
- Represents whole numbers.
- Storage depends on the size of the value (1, 2, 3, 4, 6, or 8 bytes).
Example
CREATE TABLE employees (
id INT PRIMARY KEY,
age INT NOT NULL,
department_id INT
) STRICT;
INSERT INTO employees (id, age, department_id) VALUES (1, 25, 2);
Those values will be inserted, as they adhere to the defined column type of INT
.
The following will raise an error:
INSERT INTO employees (id, age, department_id) VALUES (2, 'twenty-five', 2);
Output:
Runtime error: cannot store TEXT value in INT column employees.age (19)
Here, attempting to insert a string into an INT
column fails due to strict type enforcement.
INTEGER
INTEGER
is an alias for INT
but is often used when declaring primary keys. SQLite automatically assigns the INTEGER
column type for the ROWID
(a unique identifier for each row). An INTEGER PRIMARY KEY
column is an alias for the ROWID
, but an INT PRIMARY KEY
column is not
Characteristics
- Functions identically to
INT
in strict tables. - Alias for
ROWID
when marked asPRIMARY KEY
.
Example
CREATE TABLE products (
product_id INTEGER PRIMARY KEY,
stock INTEGER NOT NULL
) STRICT;
INSERT INTO products (stock) VALUES (50);
SELECT * FROM products;
Output:
product_id stock
---------- -----
1 50
Here, we didn’t specify a value for the primary key column and so SQLite inserted 1
.
The following will raise an error:
INSERT INTO products (stock) VALUES (50.5);
Output:
Runtime error: cannot store REAL value in INTEGER column products.stock (19)
In this case, SQLite enforces that stock
must contain only whole numbers.
REAL
REAL
represents floating-point numbers, suitable for storing values requiring precision, such as prices, measurements, or scientific data.
Characteristics
- Uses an 8-byte IEEE 754 floating-point representation.
- Supports fractional numbers.
Example
CREATE TABLE orders (
order_id INT PRIMARY KEY,
amount REAL NOT NULL
) STRICT;
INSERT INTO orders (order_id, amount) VALUES (1, 99.99);
The following will raise an error:
INSERT INTO orders (order_id, amount) VALUES (2, 'One MILLION');
Output:
Runtime error: cannot store TEXT value in REAL column orders.amount (19)
The REAL
type enforces that values must be numeric, rejecting strings or non-numeric inputs.
Bear in mind that SQLite can sometimes convert a text value into an INTEGER
or REAL
value, depending on the value It can do this if it’s a well-formed integer or real literal.
Example:
INSERT INTO orders (order_id, amount) VALUES (2, '99.99');
In this case I surrounded 99.99
in single quotes, which would normally make it a text value. However, SQLite can work out that the number is a real literal and so it inserts a REAL
value into the database.
TEXT
TEXT
stores text strings of any length, commonly used for names, descriptions, or other character data.
Characteristics
- Stores data as UTF-8, UTF-16BE, or UTF-16LE encoding.
- Allows variable-length strings.
Example
CREATE TABLE customers (
customer_id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE
) STRICT;
INSERT INTO customers (customer_id, name, email) VALUES (1, 'Aneka', '[email protected]');
That will insert the text values as expected.
However, the following will also run without error:
INSERT INTO customers (customer_id, name, email) VALUES (2, 'Fitch', 12345);
In this example, I provided an integer for the email
column, but SQLite was able to convert it to a text value.
BLOB
BLOB
(Binary Large Object) is used for storing binary data such as images, files, or serialized objects.
Characteristics
- Stores data exactly as it is without any conversion.
- Ideal for non-textual data.
Example
CREATE TABLE files (
file_id INT PRIMARY KEY,
file_name TEXT NOT NULL,
file_data BLOB NOT NULL
) STRICT;
INSERT INTO files (file_id, file_name, file_data) VALUES (1, 'image.png', x'FFD8FFE000104A464946');
The following will raise an error:
INSERT INTO files (file_id, file_name, file_data) VALUES (2, 'document.txt', 'binarydata');
Output:
Runtime error: cannot store TEXT value in BLOB column files.file_data (19)
The file_data
column expects binary input (BLOB
), rejecting any other type such as plain text.
ANY
ANY
is a flexible type introduced for scenarios where the column can store values of any data type.
Characteristics
- Accepts any data type (
INT
,INTEGER
,REAL
,TEXT
,BLOB
, orNULL
). - Useful for generic or polymorphic data.
- Provides us with flexibility even on strict tables.
Example
CREATE TABLE settings (
setting_id INT PRIMARY KEY,
name TEXT NOT NULL,
value ANY
) STRICT;
INSERT INTO settings (setting_id, name, value) VALUES (1, 'max_users', 100);
INSERT INTO settings (setting_id, name, value) VALUES (2, 'theme', 'dark');
INSERT INTO settings (setting_id, name, value) VALUES (3, 'compression', x'1F8B0800');
The ANY
type is versatile but requires careful handling to ensure logical consistency in usage.
It’s also important to note that strict tables handle ANY
columns slightly differently to regular tables:
- In regular tables, SQLite will attempt to convert strings that look like numbers into a numeric value, and if successful will store the numeric value rather than the original string.
- In strict tables on the other hand, the value is stored exactly as it was provided. No conversion is performed, regardless of the value.
Benefits of Strict Tables
- Improved Data Integrity: Strict tables enforce type constraints, reducing errors caused by inconsistent data.
- Predictable Behavior: Data types behave uniformly, leading to fewer unexpected results.
- Enhanced Debugging: Errors due to type mismatches are caught during data entry, making debugging easier.
Conclusion
SQLite’s strict table feature is a powerful enhancement for applications demanding robust data integrity and predictable behavior. By supporting well-defined data types—INT
, INTEGER
, REAL
, TEXT
, BLOB
, and ANY
—strict tables allow developers to build reliable databases while retaining SQLite’s lightweight and flexible nature.