Chapter 11: PostgreSQL ALTER COLUMN

PostgreSQL ALTER COLUMN — one of the most frequently used (and sometimes most nerve-wracking) commands when your database schema needs to evolve after data is already inside.

You’ve already learned:

  • CREATE TABLE
  • INSERT
  • SELECT
  • ADD COLUMN
  • UPDATE

Now comes ALTER COLUMN — the tool to modify properties of an existing column (not add or drop the column itself — that’s separate).

1. What is ALTER COLUMN? (Honest teacher explanation)

ALTER COLUMN is a clause inside ALTER TABLE that lets you change attributes of one specific column that already exists.

Common things you change with it:

  • Data type (TYPE)
  • Default value (SET DEFAULT / DROP DEFAULT)
  • NOT NULL constraint (SET NOT NULL / DROP NOT NULL)
  • (In newer versions) generated / identity properties
  • Collation (rare)
  • Storage parameters (advanced)

Important reality in PostgreSQL 18 (2026):

  • Changing data type is the most common use — but it can be dangerous if the conversion fails or loses data.
  • PostgreSQL is very strict: if the change would make existing data invalid → it errors and nothing happens.
  • For type changes, you almost always need a USING expression when the old and new types are not implicitly castable.
  • On large tables → type changes can take time and lock the table (rewrite in older versions; more optimized now but still careful).

Official syntax (from PostgreSQL 18 docs — postgresql.org/docs/current/sql-altertable.html):

SQL

You can chain multiple actions in one command (comma-separated).

2. Real example — evolving our students table again

Assume our current students table looks like this (after previous lessons):

SQL

Columns include:

  • id → BIGSERIAL PRIMARY KEY
  • first_name → VARCHAR(50) NOT NULL
  • last_name → VARCHAR(50) NOT NULL
  • email → VARCHAR(100) UNIQUE NOT NULL
  • gpa → NUMERIC(3,2)
  • enrollment_year → SMALLINT NOT NULL DEFAULT EXTRACT(YEAR FROM CURRENT_DATE)
  • fees_paid → BOOLEAN DEFAULT FALSE
  • phone_number → VARCHAR(15)
  • … etc.

Now the college requirements change — let’s fix some issues.

Example 1: Change data type (most common & most careful operation)

Problem: enrollment_year was SMALLINT but now we want to store future years beyond 32767 → change to INTEGER.

SQL

→ This works automatically because SMALLINT → INTEGER is safe & implicit cast exists.

Harder example: Change GPA from NUMERIC(3,2) to NUMERIC(4,2) to allow 10.00 exactly

SQL

→ Also safe — precision increases.

Tricky type change: Change phone_number from VARCHAR(15) to TEXT (unlimited length)

SQL

→ Safe.

Dangerous example: Change string to number (needs USING)

Suppose we have a bad old column old_gpa_text VARCHAR(10) with values like ‘8.75’, ‘9.2’

SQL

→ USING tells Postgres how to convert old values.

If some values are invalid (e.g. ‘abc’) → error. Fix first:

SQL

Then run the ALTER.

Example 2: Add / remove NOT NULL constraint

SQL

→ Fails if any row has NULL phone_number.

Safe way:

SQL

Reverse:

SQL

Example 3: Change / remove default value

SQL

Example 4: Multiple changes in one command (efficient)

SQL

Example 5: Rename column (also ALTER TABLE, but different clause)

SQL

(Note: this is RENAME COLUMN, not ALTER COLUMN)

3. Quick cheatsheet — most useful ALTER COLUMN actions

What you want to do Command example Risk level Notes
Change data type (safe cast) ALTER COLUMN gpa TYPE NUMERIC(4,2) Low Implicit cast ok
Change type (needs conversion) ALTER COLUMN year_text TYPE INTEGER USING year_text::INTEGER High Test with SELECT first
Make column NOT NULL ALTER COLUMN email SET NOT NULL Medium Fill NULLs first
Allow NULL again ALTER COLUMN phone DROP NOT NULL Low
Set new DEFAULT ALTER COLUMN status SET DEFAULT ‘pending’ Low Only affects new rows
Remove DEFAULT ALTER COLUMN status DROP DEFAULT Low
Multiple at once ALTER COLUMN col1 TYPE …, ALTER COLUMN col2 SET NOT NULL One statement = one lock

4. Important warnings (from real production pain)

  • Always test first → SELECT * FROM students WHERE phone_number IS NULL; before SET NOT NULL
  • Large tables + type change → can lock table for minutes/hours → do it in maintenance window
  • No direct way to change column order (position) — PostgreSQL doesn’t support reordering easily
  • If conversion fails → use USING with safe expression (e.g. NULLIF(col, ”)::numeric)
  • Backup first or use transaction: BEGIN; ALTER …; ROLLBACK; to test

Your mini practice right now

  1. Make gpa allow up to 10.00 → change to NUMERIC(4,2)
  2. Set default fees_paid to TRUE (for legacy reasons)
  3. Make phone_number nullable again if you set it NOT NULL earlier
  4. Try renaming date_of_birth to dob

Run \d students after each to see changes.

Next class?

Tell me:

  • Want DROP COLUMN or DROP TABLE next?
  • How to add / drop constraints (UNIQUE, CHECK, FOREIGN KEY) after table creation?
  • RENAME TABLE / RENAME COLUMN deeper?
  • Or back to DELETE / TRUNCATE data?

Your guru is still ON — what’s the next topic? 🚀

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *