Tables#
Tables (PostgreSQL)#
1️⃣ What is a table?#
- A table is a structured container that stores data in rows and columns.
Column → defines what kind of data can be stored
Row → one record / entry
Table → collection of related records
Example:
users
├── id
├── email
├── created_at
2️⃣ Tables live inside schemas#
From your tree:
MyDB
└── Schemas
└── public
└── Tables
- Important:
Tables are not global
Their full name is:
schema_name.table_name
Example:
public.users
3️⃣ Creating a table (basic)#
CREATE TABLE public.users (
id BIGINT GENERATED ALWAYS AS IDENTITY,
email TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT now()
);
- What happened:
A table was created
A sequence was auto-created for id
Defaults and constraints are enforced by PostgreSQL
4️⃣ Columns (what you see under “Columns”)#
- Each column has:
Data type
NULL / NOT NULL
Default
Optional constraints
Example:
email TEXT NOT NULL
- This guarantees:
Email must exist
Cannot be NULL
5️⃣ Constraints (data rules)#
Under Constraints in pgAdmin you’ll see:
Primary Key
PRIMARY KEY (id)
Uniqueness
Index-backed
Identifies the row
Unique
UNIQUE (email)
Prevents duplicates
Check
CHECK (length(email) > 5)
Enforces rules on data
Foreign Key
user_id BIGINT REFERENCES users(id)
Ensures relational integrity
6️⃣ Indexes (performance)#
Indexes speed up reads.
Example:
CREATE INDEX idx_users_email ON users(email);
Faster WHERE email = …
Slightly slower writes (normal tradeoff)
In pgAdmin:
Tables → users → Indexes
7️⃣ Triggers (automatic behavior)#
- Triggers are actions that fire:
BEFORE INSERT
AFTER UPDATE
BEFORE DELETE
Example:
CREATE TRIGGER set_updated_at
BEFORE UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION set_updated_at();
- Used for:
Audit fields
Validation
Business rules
8️⃣ Rules (advanced, rarely used)#
Rules rewrite queries internally.
- Example:
Used historically for updatable views
Avoid for new systems
Triggers are preferred
9️⃣ RLS Policies (Row Level Security)#
Under RLS Policies:
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
Example policy:
CREATE POLICY user_isolation
ON users
USING (id = current_setting('app.user_id')::bigint);
- This is production-grade security:
Database enforces access
Application cannot bypass it
🔟 Table ownership & permissions
- Every table has:
Owner
Privileges
Example:
GRANT SELECT, INSERT ON users TO app_role;
REVOKE ALL ON users FROM PUBLIC;
- Best practice:
Apps use roles
Humans use admin roles
No superuser in prod apps
1️⃣1️⃣ Table storage facts (important)#
Tables are stored as heap files
PostgreSQL uses MVCC
Updates create new row versions
VACUUM cleans old ones
You don’t manage files — PostgreSQL does.
1️⃣2️⃣ Tables vs Views vs Materialized Views#
Object |
Stores data |
Fast reads |
Auto updates |
|---|---|---|---|
Table |
✅ |
Medium |
✅ |
View |
❌ |
Slow |
✅ |
Materialized View |
✅ |
Fast |
❌ (manual refresh) |
1️⃣3️⃣ Production table checklist#
- A good production table usually has:
Primary key
Proper data types
Constraints
Indexes
Ownership set
RLS (if multi-tenant or API-driven)
- Summary
A table is a schema-scoped, rule-enforced, indexed data structure that stores records safely and efficiently in PostgreSQL.