What can ALTER TABLE ... ALTER COLUMN change, and which of those changes touch existing rows?
answer
- three things about a column can change
- default, nullability, type
- only some of them look at stored rows
- a default is a rule for inserts
- the type change must convert every value
basics
~20 sALTER COLUMN changes a column's default, its nullability and its data type. Setting or dropping a DEFAULT is metadata only and leaves stored values untouched; SET NOT NULL is checked against every existing row; a type change converts stored values and is rejected when they do not fit.
solid answer
~50 sThe three actions that matter are `SET DEFAULT` / `DROP DEFAULT`, `SET NOT NULL` / `DROP NOT NULL`, and `SET DATA TYPE`. Only the last two look at the data. Changing a default is purely a catalog change that governs future inserts which omit the column — it never rewrites a stored value, which is the opposite of `ADD COLUMN ... DEFAULT`, where the default does populate existing rows. `SET NOT NULL` is validated against every row and fails if any is NULL. A type change succeeds only if every stored value converts: widening `VARCHAR(255)` to `VARCHAR(320)` is fine, narrowing it is rejected when a value is too long. The spelling is the least portable part of SQL DDL — PostgreSQL uses `ALTER COLUMN ... TYPE`, MySQL `MODIFY COLUMN`, SQL Server `ALTER COLUMN` — and in the restate-the-definition dialects any attribute you omit is silently lost.
code
sql · 8 lines-- metadata only: rows already stored keep their qty
ALTER TABLE order_lines ALTER COLUMN qty SET DEFAULT 1;
-- validated against every existing row; fails if any qty IS NULL
ALTER TABLE order_lines ALTER COLUMN qty SET NOT NULL;
-- widening conversion; rejected if a stored value does not fit
ALTER TABLE customers ALTER COLUMN email TYPE VARCHAR(320);go deeper
Recall the three things ALTER COLUMN changes — default, nullability, data type — and the headline fact that changing a default does not change values already stored.
Sort the actions by whether they read the data: SET DEFAULT and DROP NOT NULL cannot fail on content, SET NOT NULL and a narrowing type change can. Explain the ADD COLUMN DEFAULT versus SET DEFAULT asymmetry.
Show the portability judgment: know that MySQL and SQL Server restate the whole column and silently drop omitted attributes, and describe the add-new-column-then-swap route for a conversion with no implicit cast.
Own the standard for review of type changes: which conversions may be done in place, what must be proven about the stored data first, and how the team keeps dialect-specific redefinition from quietly dropping constraints.
## The family of actions Where `ADD COLUMN` and `DROP COLUMN` change which columns exist, `ALTER COLUMN` changes an existing column in place. The actions worth knowing: ```sql ALTER TABLE order_lines ALTER COLUMN qty SET DEFAULT 1; ALTER TABLE order_lines ALTER COLUMN qty DROP DEFAULT; ALTER TABLE order_lines ALTER COLUMN qty SET NOT NULL; -- PostgreSQL spelling ALTER TABLE order_lines ALTER COLUMN qty DROP NOT NULL; -- PostgreSQL spelling ALTER TABLE customers ALTER COLUMN email TYPE VARCHAR(320); -- PostgreSQL spelling ``` Sort them by whether they inspect the data, because that is what predicts whether the statement can fail on real content that a test database never had. ## SET/DROP DEFAULT — catalog only A default is a rule applied at insert time when the column is not supplied. Changing it changes that rule from now on and nothing else: ```sql -- 1,000 rows currently have qty = 5 ALTER TABLE order_lines ALTER COLUMN qty SET DEFAULT 0; -- all 1,000 rows still have qty = 5 ``` This asymmetry is the single most reliable question in this area, because the neighbouring statement behaves the other way: `ALTER TABLE t ADD COLUMN c INT DEFAULT 0` *does* give every existing row the value 0, since the column had no value before and the default is where one comes from. Adding a column with a default backfills; altering the default of an existing column does not. To change stored values you write an `UPDATE`, and it is a separate statement with separate consequences. `DROP DEFAULT` removes the rule; the column becomes one where an omitted value means NULL again (subject to its nullability). ## Nullability — validated against the data Tightening a column to `NOT NULL` requires that no row currently holds NULL; the engine checks and rejects the statement otherwise. Loosening it (`DROP NOT NULL`) can never fail on data, since every existing value remains legal. The spelling diverges sharply. PostgreSQL and several others use the dedicated `SET NOT NULL` / `DROP NOT NULL` actions. MySQL and SQL Server express nullability as part of a full column redefinition (see below), which is where the classic accident lives. ## SET DATA TYPE — conversion, and its limits ```sql ALTER TABLE customers ALTER COLUMN email TYPE VARCHAR(320); ``` Every stored value must convert to the new type. Widening conversions — `SMALLINT` to `INTEGER`, `VARCHAR(255)` to `VARCHAR(320)`, `NUMERIC(10,2)` to `NUMERIC(14,2)` — always succeed on valid data. Narrowing is a data question, not a schema question: shortening a `VARCHAR` fails if any value is longer, shrinking numeric precision fails or truncates depending on the engine, and changing `VARCHAR` to `INTEGER` fails on the first row that is not a number. When no implicit conversion exists, PostgreSQL lets you supply one with `USING`: ```sql ALTER TABLE events ALTER COLUMN happened_at TYPE TIMESTAMP USING happened_at::timestamp; ``` That clause is PostgreSQL-specific. The portable route for a hostile conversion is the same three-step dance used elsewhere in schema evolution: add a new column of the target type, populate it with an explicit `UPDATE` that encodes the conversion rules (including what to do with values that do not convert), then swap the names. ## The restate-the-definition trap MySQL and SQL Server do not have granular per-attribute actions for the common cases; the alter restates the whole column definition, and **whatever you omit is discarded**: ```sql -- MySQL: column was VARCHAR(255) NOT NULL DEFAULT '' ALTER TABLE customers MODIFY COLUMN email VARCHAR(320); -- the column is now nullable and has no default ``` The intent was "make it longer"; the effect was "make it longer, nullable, and defaultless". SQL Server's `ALTER TABLE ... ALTER COLUMN email varchar(320)` behaves the same way with respect to nullability — omit `NOT NULL` and the column becomes nullable. The habit that prevents this is to copy the column's current definition out of the catalog and change exactly the one token you meant to change: ```sql ALTER TABLE customers MODIFY COLUMN email VARCHAR(320) NOT NULL DEFAULT ''; ``` MySQL also offers `CHANGE COLUMN old_name new_name <full definition>`, which renames and redefines at once and carries the same all-or-nothing hazard. ## Summary | action | reads existing data? | can fail on data? | |---|---|---| | `SET DEFAULT` / `DROP DEFAULT` | no | no | | `DROP NOT NULL` | no | no | | `SET NOT NULL` | yes | yes — any NULL row | | `SET DATA TYPE` (widening) | yes | practically no | | `SET DATA TYPE` (narrowing) | yes | yes — first value that does not fit |
- Why does ADD COLUMN ... DEFAULT populate existing rows while ALTER COLUMN ... SET DEFAULT does not?Because a default answers "what value when none is supplied". Adding a column leaves every existing row with no supplied value, so the default is what they get. An existing column already holds supplied values in every row, and changing the insert-time rule has no reason to overwrite them. Changing stored values is an UPDATE, deliberately a separate statement.
- A type conversion has no implicit cast — how do you get there portably?Add a new column of the target type, run an explicit UPDATE that encodes the conversion and decides what happens to values that will not convert, then swap the names and drop the old column. PostgreSQL's `ALTER COLUMN ... TYPE ... USING <expr>` does it in one statement, but that clause is not portable.
- What is the risk when a dialect expresses a type change by restating the column definition?Attributes you do not repeat are dropped. In MySQL, `MODIFY COLUMN email VARCHAR(320)` on a column that was `VARCHAR(255) NOT NULL DEFAULT ''` leaves it nullable with no default — a constraint silently removed by a statement whose intent was only to widen it. Always read the current definition from the catalog and restate it in full.
saying these in an interview costs you the question
- Thinks SET DEFAULT rewrites the values already stored
- Assumes any type change is safe because it is just metadata
- Omits NOT NULL when restating a column in MySQL or SQL Server
- Believes ALTER COLUMN syntax is the same across engines
- Says SET NOT NULL cannot fail because it is DDL