Chapter 02 · Tables, Schemas, and Data Types

Numeric, Character, Boolean, Date, Time, and Binary Types

Choose among the major SQL type families by understanding the values, operations, precision, and constraints each family represents.

Beginner65–85 minutesTypes + inspection labLast reviewed: August 2026

Learning outcomes

A data type is not merely a storage size. It communicates a value’s domain, controls valid operations, influences comparisons and sorting, and helps the DBMS reject impossible data.

01

Distinguish exact numeric, approximate numeric, character, Boolean, temporal, and binary values.

02

Explain precision, scale, range, encoding, collation, and time-zone concerns.

03

Contrast SQLite storage classes and type affinity with strongly typed server databases.

04

Create a SQLite STRICT table and inspect the runtime type of stored values.

What a data type contributes

Business value
Declared SQL type
Validation + operators
Stored representation

A sound type preserves meaning while enabling comparisons, calculations, indexing, serialization, and integrity checks.

A type answers several questions: Which values are permitted? How are they represented? Which operators and functions apply? How are values compared and sorted? What happens when an input cannot be converted?

Type concernExample question
DomainCan this column contain only whole counts, or also fractions?
RangeCan the largest valid value fit?
PrecisionMust 0.1 be represented exactly?
OrderingDoes lexical ordering match business ordering?
OperationsShould addition, date arithmetic, or pattern matching be valid?
PortabilityDoes the chosen type mean the same thing in the target engines?

Numeric types: exact versus approximate

Integers and fixed-precision decimal types are exact within their supported range. Floating-point types are approximate binary representations designed for scientific measurements and wide dynamic ranges.

I

Integer

Whole values such as counts, sequence numbers, quantities, and identifiers. Common names include SMALLINT, INTEGER, and BIGINT.

D

Decimal / numeric

Exact base-10 values with declared precision and scale, commonly used for money and regulated calculations.

F

Floating point

Approximate values such as REAL, FLOAT, and DOUBLE PRECISION. Appropriate for measurements where tiny representation error is acceptable.

P

Precision + scale

For DECIMAL(p,s), precision is the total significant decimal digits and scale is the digits after the decimal point.

For a decimal declaration such as DECIMAL(12,2), the intent is up to twelve decimal digits in total, two of them after the decimal point. Exact limits and overflow behavior remain vendor-specific.

sql · intent expressed by numeric types
CREATE TABLE invoice_line (    invoice_line_id BIGINT PRIMARY KEY,    quantity INTEGER NOT NULL,    unit_price DECIMAL(12, 2) NOT NULL,    measured_mass DOUBLE PRECISION,    CHECK (quantity > 0),    CHECK (unit_price >= 0));
Do not use binary floating point for exact currency totals

Values such as 0.1 cannot generally be represented exactly in binary floating point. Prefer an exact decimal type in server databases or an integer number of minor currency units when that model fits.

Character and text types

Character types hold textual data. Common declarations include CHAR(n), VARCHAR(n), and unbounded or large-text types such as TEXT. Their exact storage and length semantics vary by product.

  • CHAR(n) describes fixed-length character data and may pad values in some systems.
  • VARCHAR(n) describes variable-length text with a declared limit.
  • TEXT commonly describes variable-length text without a small application-level limit.
  • Unicode support depends on the DBMS, database encoding, and type family. SQL Server, for example, distinguishes VARCHAR and NVARCHAR.
  • Collation controls comparison and ordering rules such as case, accents, and locale behavior.
Stored textAppropriate column ideaPoor alternative
Email addressVariable-length character textNumeric or binary type
Country codeShort character text plus validationFree-form paragraph
Article bodyLarge textThousands of numbered columns
Machine status codeShort text or constrained codeHuman-readable sentence as the key

Boolean types

A Boolean models two logical states: true and false. PostgreSQL has a native BOOLEAN type. Other systems use aliases or compact numeric types; SQLite stores Boolean-style values as integers, conventionally 1 and 0.

sqlite · constrain a Boolean-style column
CREATE TABLE feature_flag (    flag_name TEXT PRIMARY KEY,    is_enabled INTEGER NOT NULL        CHECK (is_enabled IN (0, 1))) STRICT;INSERT INTO feature_flag VALUES ('new_catalogue', 1);-- This fails because 7 is not a valid flag value:INSERT INTO feature_flag VALUES ('unsafe_value', 7);

The check constraint turns a broad integer storage class into the intended two-value domain. This illustrates an important design principle: the declared type and constraints work together.

Date and time types

Temporal values require more decisions than “store a date.” Identify the business concept:

Business conceptTypical SQL familyExample
Calendar dateDATEA birthday or billing date
Time of dayTIMEA store opens at 09:00
Local date and timeTIMESTAMP / DATETIMEA wall-clock appointment
Global instantTime-zone-aware timestamp or normalized UTC instantAn event occurred at one moment worldwide
DurationInterval type or explicit numeric unitA job ran for 850 milliseconds

SQLite has no dedicated date/time storage class. It commonly stores ISO-8601 text, Julian day numbers, or Unix timestamps and supplies date/time functions to interpret them. Use one representation consistently and document its time-zone policy.

sqlite · ISO-8601 text and validation
CREATE TABLE audit_event (    event_id INTEGER PRIMARY KEY,    event_name TEXT NOT NULL,    occurred_at TEXT NOT NULL        CHECK (datetime(occurred_at) IS NOT NULL)) STRICT;INSERT INTO audit_event (event_name, occurred_at)VALUES ('course_opened', '2026-08-05T10:30:00Z');SELECT event_name, occurred_at, datetime(occurred_at)FROM audit_event;

Binary types

Binary types store uninterpreted bytes. Typical uses include hashes, compact protocol payloads, encrypted values, signatures, and small file fragments. Names include BINARY, VARBINARY, BYTEA, RAW, and BLOB.

Do not choose a binary type merely because a value “looks technical.” A UUID, IP address, JSON document, or image might have a specialized native type, a validated textual representation, or an external object-storage location that better supports its operations.

sqlite · insert and inspect a BLOB literal
CREATE TABLE checksum_sample (    sample_id INTEGER PRIMARY KEY,    algorithm TEXT NOT NULL,    digest BLOB NOT NULL) STRICT;INSERT INTO checksum_sample (algorithm, digest)VALUES ('demo', X'0A1B2C3D');SELECT algorithm, typeof(digest), length(digest), hex(digest)FROM checksum_sample;

SQLite storage classes and affinity

SQLite associates a storage class with each value: NULL, INTEGER, REAL, TEXT, or BLOB. Ordinary tables use type affinity and may convert inputs when possible. This flexibility differs from the stronger type enforcement many server databases apply.

SQLite conceptMeaning
Storage classThe runtime representation of one stored value
Declared typeThe type name written in the table definition
AffinitySQLite’s preference for converting and storing values in a column
STRICT tableAn optional mode that restricts declared type names and rejects incompatible values

STRICT tables support the core declarations INT, INTEGER, REAL, TEXT, BLOB, and ANY. They are excellent for this course because mistakes fail early while the environment remains lightweight.

Lab: inspect runtime types

sqlite · type-family experiment
DROP TABLE IF EXISTS type_lab;CREATE TABLE type_lab (    sample_id INTEGER PRIMARY KEY,    whole_count INTEGER NOT NULL,    measured_value REAL,    description TEXT,    raw_payload BLOB,    flexible_value ANY) STRICT;INSERT INTO type_lab    (whole_count, measured_value, description, raw_payload, flexible_value)VALUES    (12, 19.75, 'first sample', X'CAFE', '00123'),    (0, NULL, 'missing measurement', X'', 123);SELECT    sample_id,    typeof(whole_count) AS count_type,    typeof(measured_value) AS measure_type,    typeof(description) AS description_type,    typeof(raw_payload) AS payload_type,    typeof(flexible_value) AS flexible_typeFROM type_lab;-- Expected to fail in a STRICT table:INSERT INTO type_lab (whole_count) VALUES ('twelve');

Run the query and compare the declared type with typeof(), which reports the runtime storage class. Notice that the ANY column preserves the difference between text '00123' and integer 123.

Extend the lab

  1. Add an is_verified integer column constrained to 0 or 1.
  2. Add a textual UTC timestamp and validate it with datetime().
  3. Insert 0.1 + 0.2 into a REAL column and inspect the displayed result.
  4. Attempt incompatible values in each STRICT column and record the error messages.

Common mistakes

Choosing a type from sample data only

Ten sample rows cannot establish the full range, precision, or future operations. Use business rules and expected growth.

Storing dates in locale-specific text

Values such as 08/05/26 are ambiguous. Use a native temporal type or a documented, sortable representation such as ISO 8601.

Using text for every value

Text can store almost anything but weakens validation and makes numeric, temporal, and Boolean operations harder or unsafe.

Assuming the same type name behaves identically everywhere

Length semantics, implicit conversions, ranges, time zones, and aliases vary. Portability requires testing, not just matching names.

Checkpoint and practice

Concept check

  1. Why is DECIMAL usually preferable to floating point for exact money?
  2. What is the difference between a calendar date and a global instant?
  3. How does a SQLite storage class differ from a declared column type?
  4. When is a binary type more appropriate than text?
Review the answers

Decimal arithmetic represents supported base-10 values exactly; floating point is approximate. A date identifies a day, while an instant identifies one point on the global timeline. SQLite stores a runtime class per value and applies affinity from the declaration. Binary types are appropriate when the value is fundamentally bytes and byte-level operations are required.

Summary and next lesson

Data-type families express more than storage: they preserve domains, enable valid operations, and support integrity. The next lesson turns these families into a repeatable selection process for real fields such as identifiers, money, measurements, dates, statuses, and flags.

References

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only assets compatible with the Ethereum/ERC-20 network. Do not send TRC-20/TRON assets.