CREATE TABLE defines a new, empty table with specified columns, data types, and constraints.
CREATE TABLE is PostgreSQL’s workhorse for building schemas. Mastering its syntax lets you design stable, efficient databases that fit your application from day one.
CREATE TABLE builds a brand-new table in the current database. You specify each column’s name, data type, defaults, and constraints so PostgreSQL can enforce data integrity automatically.
The core pattern is CREATE TABLE table_name (column_definitions, table_constraints);
. Brackets hold comma-separated column specs followed by any table-level constraints.
Start every column with a name and a type: id SERIAL
, email TEXT
, price NUMERIC(10,2)
. Add modifiers such as NOT NULL
or DEFAULT now()
right after the type.
Declare one or more columns as the unique identifier: PRIMARY KEY(id)
or inline id SERIAL PRIMARY KEY
.
Reference another table to maintain relational integrity: FOREIGN KEY (user_id) REFERENCES users(id)
.
Use UNIQUE(email)
to prevent duplicates and CHECK(price > 0)
to enforce logical rules.
Combine CREATE TABLE
with AS SELECT
to clone structure and rows: CREATE TABLE active_users AS SELECT * FROM users WHERE is_active;
No constraints are copied; add them later with ALTER TABLE
.
Use meaningful names, pick the smallest sufficient data type, prefer GENERATED ALWAYS AS IDENTITY
over old SERIAL
, and index foreign keys immediately to avoid future scans.
Don’t forget schema qualification (public.orders
) in multi-schema databases. Avoid unbounded VARCHAR
; cap it to expected length for faster checks.
CREATE TABLE public.orders (
order_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
user_id BIGINT NOT NULL,
status TEXT NOT NULL DEFAULT 'pending',
total_cents INTEGER CHECK (total_cents >= 0),
created_at TIMESTAMPTZ DEFAULT now(),
FOREIGN KEY (user_id) REFERENCES public.users(id)
);
Immediately seed lookup tables, create needed indexes, and write sample inserts to validate constraints. Keep your DDL in version control for repeatable deployments.
Yes. Run ALTER TABLE ... ADD COLUMN
. PostgreSQL fills existing rows with the column’s default or NULL.
Issue DROP TABLE IF EXISTS table_name CASCADE;
to remove it and any dependent objects. Use cautiously in production.
SERIAL
creates a sequence behind the scenes, while GENERATED ... AS IDENTITY
is SQL-standard, easier to manage, and preferred for new designs.
It only takes a brief lock on the new table’s name—no impact on existing tables. Other sessions continue unaffected.
Yes. Use CREATE TABLE new LIKE old INCLUDING CONSTRAINTS;
to duplicate columns and constraints in one step.