SQL Basics
CREATE, INSERT, SELECT — DDL and DML fundamentals
With a database and schema in place from Architecture, this covers the SQL you'll use constantly: defining tables and moving rows in and out of them.
Creating structure
CREATE TABLE users (
id serial PRIMARY KEY,
email text NOT NULL UNIQUE,
full_name text,
created_at timestamptz NOT NULL DEFAULT now()
);A few constraints worth knowing by default:
serialallocates an auto-incrementing integer backed by a sequence — the modern equivalent, preferred in new schemas, isGENERATED ALWAYS AS IDENTITY.NOT NULLandUNIQUEare enforced on every write, not advisory.DEFAULT now()fills the column automatically if the INSERT doesn't specify it.
CREATE TABLE users (
id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
email text NOT NULL UNIQUE,
full_name text,
created_at timestamptz NOT NULL DEFAULT now()
);ALTER TABLE and DROP TABLE work as you'd expect — Postgres will
enforce constraints on ALTER TABLE ... ADD CONSTRAINT against
existing data, and DROP TABLE takes an ACCESS EXCLUSIVE lock (see
Locks & Deadlocks).
Moving rows
INSERT INTO users (email, full_name) VALUES
('ada@example.com', 'Ada Lovelace'),
('alan@example.com', 'Alan Turing');
UPDATE users SET full_name = 'A. Lovelace' WHERE email = 'ada@example.com';
DELETE FROM users WHERE email = 'alan@example.com';
SELECT id, email, full_name FROM users WHERE created_at > now() - interval '1 day';UPDATE and DELETE here are ordinary, fast, row-targeted operations — not batch rewrites.
This is where Postgres's SQL diverges most visibly from
ClickHouse's dialect. ClickHouse treats
UPDATE/DELETE as heavyweight asynchronous mutations and doesn't
enforce NOT NULL or foreign keys by default, because it's
optimized for append-heavy analytical ingestion, not row-level
editing. Postgres enforces every constraint immediately and expects
UPDATE/DELETE to be routine — that's the OLTP contract from
Why PostgreSQL.
Next: Data Types — picking the right column types for what you're storing.