DDL, Data Types and Constraints
Know how tables, data types and constraints really behave: what PostgreSQL enforces, what it rounds or rejects, and how DDL changes lock and rewrite data.
Key points
- 1
A primary key is UNIQUE plus NOT NULL; UNIQUE allows many NULLs unless declared NULLS NOT DISTINCT (PostgreSQL 15+), and CHECK passes when its condition is NULL.
- 2
Use
numericfor exact decimals andtimestamptzfor real-world instants; float is approximate and plaintimestampsilently drops offsets. - 3
Prefer
GENERATED ALWAYS AS IDENTITYover serial. Neither is gap-free or unique by itself: sequences never roll back, and explicit ids don't advance them. - 4
Foreign keys default to NO ACTION, are not auto-indexed on the referencing column in PostgreSQL, and MATCH SIMPLE skips the check when any key column is NULL.
- 5
DELETE fires row triggers and keeps sequences; TRUNCATE is fast, transactional in PostgreSQL, skips row triggers and resets identity only with RESTART IDENTITY; DROP ... CASCADE drops dependent constraints and views, not child tables.
- 6
ALTER TABLE ADD COLUMN with a non-volatile default is metadata-only, while a volatile default or a type change with USING rewrites the table under an exclusive lock.
- 7
For big tables, add constraints with NOT VALID and VALIDATE them later, and add NOT NULL via a validated CHECK to avoid long blocking scans.
Common traps
An unquoted identifier is folded to lowercase, so a table created as "Users" can't be found as Users.
TRUNCATE parent CASCADEempties every referencing table, andDROP TABLE parent CASCADEsilently removes the child's foreign key.SQLite doesn't enforce column types (without STRICT), VARCHAR lengths, or foreign keys (without PRAGMA foreign_keys = ON).
Test yourself on DDL, Data Types and Constraints
Ten questions, with the answer and explanation after each one.