ALTER TABLE & DROP TABLE
Evolve your schema — add columns, rename tables, clean up
Changing Your Schema
Tables are not set in stone — real systems evolve. ALTER TABLE changes an existing table's structure; DROP TABLE removes it entirely. Here's the practical picture:
ALTER TABLE t ADD COLUMN priority TEXT DEFAULT 'normal' adds a column to an existing table; existing rows immediately get the DEFAULT value. This is safe, fast, and backward-compatible (old queries still work).ALTER TABLE t RENAME TO new_name works in all major databases. ALTER TABLE t RENAME COLUMN old TO new is supported in SQLite 3.25+, Postgres, and MySQL 8+. Rename operations are fast — they're metadata-only, no data movement.ALTER TABLE t ALTER COLUMN c TYPE new_type in Postgres. ALTER TABLE t MODIFY c new_type in MySQL. SQLite does not support type changes directly — recreate the table if needed. Type changes are one of the riskier schema operations because existing data may not convert cleanly.DROP TABLE t deletes the table and all its rows, indexes, and triggers. Irreversible. There's no "undo" — only backups save you. Use DROP TABLE IF EXISTS t to avoid an error if the table doesn't exist. Consider renaming to t_deleted_YYYYMMDD first as a safety net before dropping.DROP TABLE t CASCADE (Postgres) also drops dependent objects. SQLite with PRAGMA foreign_keys = ON prevents the drop unless you handle FKs first.How ALTER / DROP Work
Evolve and remove tables
- ALTER TABLE ADD COLUMN — safest change, backward compatible
- ALTER TABLE RENAME TO / RENAME COLUMN — metadata only
- ALTER TABLE DROP COLUMN — SQLite 3.35+, Postgres, MySQL
- DROP TABLE — irreversible; the data is gone
ADD COLUMN Variants
NULL vs DEFAULT behavior
Schema Change Traps
Things that bite
- DROP TABLE is irreversible — rename first, drop later
- Adding NOT NULL without DEFAULT fails on non-empty tables
- SQLite: ALTER COLUMN TYPE is not supported — recreate instead
- Postgres: ALTER can rewrite the whole table (downtime)
Safer Alternatives
Production-safe migration habits
- Backup before DROP
- Use IF EXISTS / IF NOT EXISTS for re-runnable scripts
- Rename to _deleted_YYYYMMDD before dropping
- Test ALTER on a copy of production first
ADD COLUMN ... DEFAULTAdd a column with a default value for existing rowsRENAME TO / RENAME COLUMNRename table or column — metadata-only operationDROP COLUMNRemove a column — may rewrite the table on older versionsDROP TABLE IF EXISTSRemove the table; IF EXISTS prevents errors if already goneWorked Example
Create a tasks table, seed two rows, then add a priority column with a default, and finally rename the table to work_items.
ALTER TABLE tasks ADD COLUMN priority TEXT DEFAULT 'normal' adds the new column and immediately fills it with "normal" for both existing rows — no separate UPDATE needed. Then RENAME TO work_items renames the table without touching any data. PRAGMA table_info confirms the final schema has four columns.| id | title | done | priority |
|---|---|---|---|
| 1 | Write query | 0 | normal |
| 2 | Review PR | 0 | normal |
DROP TABLE without a backup
Once dropped, the rows are gone. Not "moved to archive," not "soft-deleted" — gone. Recovering requires a backup (if you have one) or point-in-time recovery (if your database supports it).
Before dropping production data, rename first as insurance: ALTER TABLE orders RENAME TO orders_deleted_20240420;. Keep the renamed table for a week, then drop.
ADD COLUMN NOT NULL without DEFAULT on a non-empty table
Existing rows have no value for the new column — but NOT NULL refuses NULL values. The ALTER fails with a constraint error on most databases (Postgres, MySQL). SQLite allows it but treats existing values as if the column didn't exist until set.
Add the column with a DEFAULT first: ADD COLUMN phone TEXT NOT NULL DEFAULT 'unknown'. Or add it nullable, backfill values, then change to NOT NULL.
Key Concepts
Pro Tip
Schemas are never done. Adding columns is the most common kind of change; doing it without locking the table for hours (on big systems) requires understanding what each operation costs.
When to Use
Adding new fields as features ship, renaming tables during refactors, dropping staging tables after successful migrations, deprecating old columns.