【SQL】ALTER TABLE完全ガイド|列追加・削除・型変更・RENAME・制約操作・Online DDL・RDBMS別構文まで解説

【SQL】ALTER TABLE完全ガイド|列追加・削除・型変更・RENAME・制約操作・Online DDL・RDBMS別構文まで解説 SQL

サービスの成長とともに、既存テーブルに新しいカラムを追加したり、型のサイズが足りなくなって変更したり、不要になった列を削除したりする作業は頻繁に発生します。

そのたびに使うのが ALTER TABLE です。ただし 数千万行のテーブルに ALTER TABLE を実行すると本番テーブルが長時間ロックされるなど、本番環境では慎重に扱う必要があります。

この記事では列の追加・削除・変更・名前変更・制約操作の基本構文から、MySQL・PostgreSQL・SQL Server の RDBMS 別の違い、本番での安全な Online DDL まで体系的に解説します。

サンプルテーブル(以降の例で使用)
-- 変更前の employees テーブル
CREATE TABLE employees (
    id         INT PRIMARY KEY AUTO_INCREMENT,
    name       VARCHAR(100) NOT NULL,
    email      VARCHAR(200),
    salary     INT,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- テーブル構造の確認(MySQL)
DESCRIBE employees;
-- または
SHOW CREATE TABLE employees\G

-- テーブル構造の確認(PostgreSQL)
\d employees

-- テーブル構造の確認(SQL Server)
EXEC sp_help 'employees';
スポンサーリンク

列の追加(ADD COLUMN)

ALTER TABLE テーブル名 ADD COLUMN 列名 データ型 [オプション] で列を追加します。追加した列は既存の行に対してデフォルト値(指定がなければ NULL)が設定されます。

基本的な列の追加
-- 列を追加(末尾に追加)
ALTER TABLE employees ADD COLUMN phone VARCHAR(20);

-- NOT NULL + DEFAULT を指定して追加
ALTER TABLE employees ADD COLUMN status VARCHAR(20) NOT NULL DEFAULT 'active';

-- 複数列を一括追加(MySQL / Oracle)
ALTER TABLE employees
    ADD COLUMN dept_id INT,
    ADD COLUMN resigned_at DATE;

-- PostgreSQL / SQL Server: 複数列を一括追加
ALTER TABLE employees
    ADD COLUMN dept_id INT,
    ADD COLUMN resigned_at DATE;  -- 同じ構文で OK

-- NOT NULL 列を既存テーブルに追加する場合
-- → 既存行に NULL が入れられないため DEFAULT 値が必須
ALTER TABLE employees
    ADD COLUMN version INT NOT NULL DEFAULT 1;
-- 既存行はすべて version = 1 になる
MySQL: 追加位置の指定(FIRST / AFTER)
-- 先頭に追加
ALTER TABLE employees ADD COLUMN code VARCHAR(10) FIRST;

-- 特定の列の後ろに追加
ALTER TABLE employees ADD COLUMN nickname VARCHAR(100) AFTER name;

-- ※ FIRST / AFTER は MySQL 独自構文
-- PostgreSQL・SQL Server では位置指定不可(末尾にしか追加できない)
-- → 並び順を変えたい場合は ALTER TABLE ... テーブル再作成が必要
列の追加と NOT NULL 制約の組み合わせ:
データが入っている既存テーブルに NOT NULL 列を追加する場合は必ず DEFAULT 値 を指定してください。DEFAULT を指定しないと「既存行に NULL を入れられない」のでエラーになります。後から DEFAULT を削除したい場合は追加後に ALTER TABLE ... ALTER COLUMN ... DROP DEFAULT(PostgreSQL)などで対応できます。

列の削除(DROP COLUMN)

ALTER TABLE テーブル名 DROP COLUMN 列名 で列を削除します。削除した列のデータは元に戻せないため、事前にバックアップを取ることを強く推奨します。

列の削除
-- 列を削除
ALTER TABLE employees DROP COLUMN phone;

-- 複数列を一括削除(MySQL)
ALTER TABLE employees
    DROP COLUMN dept_id,
    DROP COLUMN resigned_at;

-- 存在チェック付きで削除(MySQL 8.0 / PostgreSQL 9.0 以降)
-- MySQL 8.0 以降
ALTER TABLE employees DROP COLUMN IF EXISTS phone;

-- PostgreSQL
ALTER TABLE employees DROP COLUMN IF EXISTS phone;

-- ===== 削除前の確認 =====
-- MySQL: 参照しているインデックス・制約の確認
SHOW CREATE TABLE employees\G
-- → KEY や CONSTRAINT で phone を参照していると DROP COLUMN がエラーになる

-- 外部キーが参照している列は先に外部キーを削除してから
ALTER TABLE employees DROP FOREIGN KEY fk_dept;  -- 外部キー削除
ALTER TABLE employees DROP COLUMN dept_id;         -- その後に列削除
DROP COLUMN は即座に取り消せません:
DROP COLUMN を実行するとそのカラムのデータは完全に失われます。本番環境では必ず事前にバックアップを取得し、影響範囲(アプリコード・VIEW・プロシージャ)を確認してから実行してください。PostgreSQL にはすぐに物理削除しない SET UNUSED に相当する機能はありませんが、一度 RENAME COLUMN で無効化してから後で削除する方法が使われることもあります。

列のデータ型・サイズ・制約の変更(MODIFY / ALTER COLUMN)

列の型・サイズ・デフォルト値・NULL 制約を変更するには RDBMS によって構文が異なります。

操作 MySQL PostgreSQL SQL Server
型・サイズ変更 MODIFY COLUMN 列名 新型 ALTER COLUMN 列名 TYPE 新型 ALTER COLUMN 列名 新型
列名変更 RENAME COLUMN 旧名 TO 新名(8.0+)
CHANGE 旧名 新名 型(旧構文)
RENAME COLUMN 旧名 TO 新名 EXEC sp_rename 'テーブル.旧名', '新名', 'COLUMN'
NOT NULL 追加 MODIFY COLUMN 列名 型 NOT NULL ALTER COLUMN 列名 SET NOT NULL ALTER COLUMN 列名 型 NOT NULL
NOT NULL 削除 MODIFY COLUMN 列名 型 NULL ALTER COLUMN 列名 DROP NOT NULL ALTER COLUMN 列名 型 NULL
DEFAULT 追加 MODIFY COLUMN 列名 型 DEFAULT 値 ALTER COLUMN 列名 SET DEFAULT 値 ADD CONSTRAINT df_name DEFAULT 値 FOR 列名
DEFAULT 削除 MODIFY COLUMN 列名 型(DEFAULT 指定なし) ALTER COLUMN 列名 DROP DEFAULT DROP CONSTRAINT df_name
型・サイズの変更(MySQL)
-- VARCHAR(100) → VARCHAR(200) に拡張
ALTER TABLE employees MODIFY COLUMN name VARCHAR(200) NOT NULL;

-- INT → BIGINT に変更(より大きな整数が必要になった場合)
ALTER TABLE employees MODIFY COLUMN salary BIGINT;

-- 型変換に注意: データが入っている場合、互換性のない型変換はエラー
-- NG: VARCHAR(5) に「123456」が入っている列を VARCHAR(3) に縮小 → エラー
-- NG: '2024-01-15' が入っている VARCHAR 列を INT に変換 → エラー
ALTER TABLE employees MODIFY COLUMN code INT;  -- 文字が入っていると失敗

-- 安全な型変換のパターン
-- 1. 新しい列を追加
ALTER TABLE employees ADD COLUMN salary_new DECIMAL(12,2);
-- 2. データを変換してコピー
UPDATE employees SET salary_new = CAST(salary AS DECIMAL(12,2));
-- 3. 古い列を削除
ALTER TABLE employees DROP COLUMN salary;
-- 4. 列名を変更
ALTER TABLE employees RENAME COLUMN salary_new TO salary;
型・サイズの変更(PostgreSQL)
-- VARCHAR(100) → VARCHAR(200) に拡張
ALTER TABLE employees ALTER COLUMN name TYPE VARCHAR(200);

-- PostgreSQL は一部の型変換に USING 句が必要
-- TEXT → INTEGER に変換(キャスト式を指定)
ALTER TABLE employees ALTER COLUMN salary TYPE BIGINT USING salary::BIGINT;

-- VARCHAR → DATE に変換(フォーマットが合っていれば)
ALTER TABLE employees ALTER COLUMN resigned_at TYPE DATE
    USING resigned_at::DATE;

-- NOT NULL 制約の追加・削除
ALTER TABLE employees ALTER COLUMN email SET NOT NULL;
ALTER TABLE employees ALTER COLUMN email DROP NOT NULL;

-- DEFAULT の追加・削除
ALTER TABLE employees ALTER COLUMN status SET DEFAULT 'active';
ALTER TABLE employees ALTER COLUMN status DROP DEFAULT;
型・サイズの変更(SQL Server)
-- VARCHAR(100) → VARCHAR(200) に拡張
ALTER TABLE employees ALTER COLUMN name VARCHAR(200) NOT NULL;

-- NOT NULL 制約の追加(型も一緒に指定が必要)
ALTER TABLE employees ALTER COLUMN email VARCHAR(200) NOT NULL;

-- NOT NULL 制約の削除(NULL 許容に変更)
ALTER TABLE employees ALTER COLUMN email VARCHAR(200) NULL;

-- DEFAULT 制約の追加(制約名付きで追加)
ALTER TABLE employees
ADD CONSTRAINT df_employees_status DEFAULT 'active' FOR status;

-- DEFAULT 制約の削除(制約名を指定)
ALTER TABLE employees DROP CONSTRAINT df_employees_status;

-- DEFAULT 制約名を確認する
SELECT name FROM sys.default_constraints
WHERE parent_object_id = OBJECT_ID('employees')
  AND parent_column_id = COLUMNPROPERTY(
      OBJECT_ID('employees'), 'status', 'ColumnId');

列名の変更(RENAME COLUMN)

列名を変更するには RDBMS によって構文が異なります。データ型を保持したまま名前だけを変えます。

列名の変更(RDBMS 別)
-- ===== MySQL 8.0+ =====
ALTER TABLE employees RENAME COLUMN email TO email_address;

-- MySQL 5.7 以前: CHANGE(型の再指定が必要)
ALTER TABLE employees CHANGE email email_address VARCHAR(200);
-- 構文: CHANGE 旧列名 新列名 データ型 [オプション]

-- ===== PostgreSQL =====
ALTER TABLE employees RENAME COLUMN email TO email_address;

-- ===== SQL Server =====
EXEC sp_rename 'employees.email', 'email_address', 'COLUMN';

-- ===== RENAME COLUMN の注意点 =====
-- ビュー・ストアドプロシージャ・外部キー制約が旧列名を参照している場合は
-- それらも一緒に変更が必要
-- 依存関係の確認(PostgreSQL)
SELECT dependent_ns.nspname, dependent_view.relname
FROM pg_depend
JOIN pg_rewrite ON pg_depend.objid = pg_rewrite.oid
JOIN pg_class AS dependent_view ON pg_rewrite.ev_class = dependent_view.oid
JOIN pg_class AS source_table ON pg_depend.refobjid = source_table.oid
JOIN pg_namespace dependent_ns ON dependent_ns.oid = dependent_view.relnamespace
WHERE source_table.relname = 'employees';

テーブル名の変更(RENAME TABLE)

テーブル名の変更(RDBMS 別)
-- ===== MySQL =====
RENAME TABLE employees TO staff;
-- 複数テーブルを一括変更(アトミック操作)
RENAME TABLE employees TO staff, departments TO depts;

-- または
ALTER TABLE employees RENAME TO staff;

-- ===== PostgreSQL =====
ALTER TABLE employees RENAME TO staff;

-- ===== SQL Server =====
EXEC sp_rename 'employees', 'staff';
-- または(スキーマ付き)
EXEC sp_rename 'dbo.employees', 'staff';

-- ===== テーブル名変更の注意点 =====
-- ・ビュー・外部キー・ストアドプロシージャが旧テーブル名を参照していれば変更が必要
-- ・アプリケーションコードの SQL も変更が必要
-- ・MySQL の RENAME TABLE はアトミックに実行されロールバックも可能

制約の追加と削除(NOT NULL / UNIQUE / FK / CHECK)

ALTER TABLE で制約を後付けで追加・削除できます。

UNIQUE 制約の追加・削除
-- UNIQUE 制約の追加(列単位)
ALTER TABLE employees ADD CONSTRAINT uq_email UNIQUE (email);

-- UNIQUE インデックスとして追加(MySQL では等価)
CREATE UNIQUE INDEX uq_email ON employees (email);

-- UNIQUE 制約の削除
-- MySQL
ALTER TABLE employees DROP INDEX uq_email;
-- PostgreSQL / SQL Server
ALTER TABLE employees DROP CONSTRAINT uq_email;

-- 複合 UNIQUE(email + dept_id の組み合わせが一意)
ALTER TABLE employees ADD CONSTRAINT uq_email_dept UNIQUE (email, dept_id);
外部キー(FOREIGN KEY)の追加・削除
-- CREATE TABLE departments (dept_id INT PRIMARY KEY, dept_name VARCHAR(100));

-- 外部キーの追加
ALTER TABLE employees
ADD CONSTRAINT fk_dept
FOREIGN KEY (dept_id) REFERENCES departments(dept_id)
ON DELETE SET NULL    -- 親が削除されたら NULL にする
ON UPDATE CASCADE;    -- 親が更新されたら連動して更新

-- 外部キーの削除
-- MySQL
ALTER TABLE employees DROP FOREIGN KEY fk_dept;
-- PostgreSQL / SQL Server
ALTER TABLE employees DROP CONSTRAINT fk_dept;

-- 外部キー名の確認(MySQL)
SELECT CONSTRAINT_NAME
FROM information_schema.TABLE_CONSTRAINTS
WHERE TABLE_NAME = 'employees'
  AND CONSTRAINT_TYPE = 'FOREIGN KEY';

-- 外部キーの一時的な無効化(MySQL)
SET FOREIGN_KEY_CHECKS = 0;
-- バルクインサートなど実行
SET FOREIGN_KEY_CHECKS = 1;

-- 外部キーの一時的な無効化(PostgreSQL)
ALTER TABLE employees DISABLE TRIGGER ALL;  -- 外部キーを含むトリガー無効化
ALTER TABLE employees ENABLE TRIGGER ALL;
CHECK 制約の追加・削除
-- CHECK 制約の追加(salary が 0 以上)
ALTER TABLE employees
ADD CONSTRAINT chk_salary CHECK (salary >= 0);

-- CHECK 制約(status の値制限)
ALTER TABLE employees
ADD CONSTRAINT chk_status CHECK (status IN ('active', 'inactive', 'resigned'));

-- CHECK 制約の削除
ALTER TABLE employees DROP CONSTRAINT chk_salary;

-- MySQL 8.0 以前は CHECK を構文として受け付けるが無視する
-- MySQL 8.0.16 以降で CHECK 制約が有効になった
PRIMARY KEY の追加・削除については【SQL】プライマリーキーの追加と削除で詳しく解説しています。

複数の変更を一括実行する

MySQL では一つの ALTER TABLE 文に複数の操作をまとめられます。一括実行することでテーブルの再構築(テーブルスキャン)が1回で済み、複数回に分けるよりパフォーマンスが向上します。

複数操作を一括実行(MySQL)
-- 複数の変更を 1 つの ALTER TABLE にまとめる
ALTER TABLE employees
    ADD COLUMN dept_id INT,
    ADD COLUMN resigned_at DATE,
    ADD COLUMN version INT NOT NULL DEFAULT 1,
    MODIFY COLUMN name VARCHAR(200) NOT NULL,
    DROP COLUMN phone,
    ADD CONSTRAINT uq_email UNIQUE (email),
    ADD CONSTRAINT fk_dept FOREIGN KEY (dept_id) REFERENCES departments(dept_id);

-- ※ 複数回に分けると毎回テーブルが再構築される(大量データで時間がかかる)
-- 1回にまとめると再構築が1回で済む → 実行時間を大幅に短縮できる
複数操作を一括実行(PostgreSQL)
-- PostgreSQL でも複数操作を一括実行可能
ALTER TABLE employees
    ADD COLUMN dept_id INT,
    ADD COLUMN resigned_at DATE,
    ALTER COLUMN name TYPE VARCHAR(200),
    ALTER COLUMN email SET NOT NULL,
    DROP COLUMN phone;

-- PostgreSQL では ALTER TABLE 全体がトランザクション内で実行される
-- 途中でエラーが起きればすべてロールバック

本番での ALTER TABLE の注意点とオンライン DDL

数千万〜数億行のテーブルに通常の ALTER TABLE を実行すると、テーブルが長時間ロックされアプリケーションが応答しなくなることがあります。本番環境では Online DDL や専用ツールを活用してください。

RDBMS Online DDL の仕組み ロック発生条件
MySQL 5.6+(InnoDB) 多くの操作が ALGORITHM=INPLACE で Online 実行可能 一部の操作(型変更など)は ALGORITHM=COPY でテーブルロックが発生
MySQL 8.0+ INSTANT COLUMN ADD(即座に追加・テーブル再構築なし) DEFAULT 値なしの NOT NULL 列追加など一部はフルコピー
PostgreSQL ADD COLUMN WITH DEFAULT は即座(PG11+)。インデックス追加は CONCURRENTLY で可能 大部分の DDL は短時間の ACCESS EXCLUSIVE ロックを取得
SQL Server Online Index Rebuild(Enterprise Edition) Standard Edition では多くの DDL でロックが発生
MySQL の Online DDL オプション(ALGORITHM / LOCK)
-- ALGORITHM=INSTANT: テーブル再構築なしで即座に完了(MySQL 8.0+、列追加に対応)
ALTER TABLE employees
    ADD COLUMN score INT DEFAULT 0,
    ALGORITHM=INSTANT;  -- テーブルロックなし・即座に完了

-- ALGORITHM=INPLACE: テーブルをコピーせず変更(多くの操作で利用可能)
ALTER TABLE employees
    ADD INDEX idx_dept (dept_id),
    ALGORITHM=INPLACE, LOCK=NONE;  -- 読み書き並行実行可能

-- ALGORITHM=COPY: テーブル全体をコピー(古い動作・ロック発生)
ALTER TABLE employees
    MODIFY COLUMN salary BIGINT,
    ALGORITHM=COPY;  -- 大テーブルでは時間がかかる

-- LOCK=DEFAULT / NONE / SHARED / EXCLUSIVE
-- LOCK=NONE: 読み書き両方を並行許可(不可能な操作はエラー)
-- LOCK=SHARED: 読み取りのみ並行(書き込みは待ち)
-- LOCK=EXCLUSIVE: 全操作を直列化

-- どのアルゴリズムが使われるか確認(試してみる)
-- ALGORITHM=INSTANT がサポートされなければエラーになる(実際の変更は起きない)
ALTER TABLE employees ADD COLUMN tmp INT, ALGORITHM=INSTANT;
PostgreSQL の CONCURRENTLY オプション(インデックス)
-- 通常のインデックス作成(テーブルを短時間ロック)
CREATE INDEX idx_emp_email ON employees (email);

-- CONCURRENTLY: テーブルをロックせずにインデックス作成(時間はかかる)
CREATE INDEX CONCURRENTLY idx_emp_email ON employees (email);
-- → 読み書き並行実行中でもインデックスを作成できる
-- → ただし通常より時間がかかり、失敗すると INVALID インデックスが残る

-- INVALID インデックスの確認と削除
SELECT schemaname, tablename, indexname, indexdef
FROM pg_indexes
WHERE tablename = 'employees'
  AND indexname = 'idx_emp_email';

-- PostgreSQL 11 以降: DEFAULT 値付き列の追加が即座(テーブルスキャンなし)
ALTER TABLE employees ADD COLUMN score INT DEFAULT 0;
-- PG10 以前: 全行を更新するためテーブルスキャンが発生
大量テーブル向けの外部ツール(MySQL)
-- pt-online-schema-change(Percona Toolkit)
-- テーブルをコピーしながら変更・元テーブルをアトミックにリネーム
-- → 数億行のテーブルでも無停止で ALTER TABLE 相当の操作が可能

-- 実行コマンド例(コマンドライン)
-- pt-online-schema-change \
--   --alter "ADD COLUMN score INT DEFAULT 0" \
--   --execute \
--   D=mydb,t=employees

-- gh-ost(GitHub 製)
-- バイナリログを利用したオンラインスキーマ変更ツール
-- より安全で進捗管理・一時停止・再開が可能

-- gh-ost 実行コマンド例
-- gh-ost \
--   --database="mydb" \
--   --table="employees" \
--   --alter="ADD COLUMN score INT DEFAULT 0" \
--   --execute

-- どちらも大きなテーブルで ALTER TABLE を安全に実行するための定番ツール
本番 ALTER TABLE 実行前のチェックリスト:

  • テーブルサイズの確認: 数百万行を超えるテーブルは Online DDL ツールの利用を検討する
  • ALGORITHM=INSTANT の確認: MySQL 8.0 なら列追加は INSTANT で即座に完了するか試す
  • 実行時間の見積もり: ステージング環境で同等サイズのテーブルで事前にテスト
  • ロック影響範囲: 実行中に待ちが発生するクエリがないか ロック状態を監視する
  • バックアップ: DROP COLUMN・型変更の前は必ずバックアップを取得
  • 依存関係の確認: VIEW・ストアドプロシージャ・アプリコードが影響を受けないか確認

ALTER TABLE でよくあるエラーと対処法

エラー RDBMS 原因 対処法
Column count doesn't match... MySQL INSERT INTO … SELECT のカラム数が合わない SELECT 列数を INSERT 先と合わせる
Cannot add or update a child row: a foreign key constraint fails MySQL 外部キー制約のある列に制約に違反する値を追加しようとした 先に親テーブルのデータを整合させるか SET FOREIGN_KEY_CHECKS=0 で一時無効化
Invalid use of NULL value MySQL NULL が入っている列に NOT NULL を追加しようとした 先に UPDATE ... WHERE col IS NULL で NULL を解消してから制約を追加
column "x" of relation "y" already exists PostgreSQL 既存の列名と同じ名前で ADD COLUMN しようとした 別の名前を使うか ADD COLUMN IF NOT EXISTS(PG9.6+)を使う
Lock wait timeout exceeded MySQL 長時間実行されているクエリがテーブルをロック中 SHOW PROCESSLIST で原因クエリを特定して KILL
data type incompatible PostgreSQL USING 句なしに互換性のない型変換を試みた USING 列名::新型 でキャスト式を明示する
NOT NULL 追加前の NULL 解消パターン
-- ① 現在の NULL 状況を確認
SELECT COUNT(*) FROM employees WHERE email IS NULL;

-- ② NULL 行を更新してから制約を追加
UPDATE employees SET email = 'unknown@example.com' WHERE email IS NULL;

-- ③ NOT NULL 制約を追加
-- MySQL
ALTER TABLE employees MODIFY COLUMN email VARCHAR(200) NOT NULL;
-- PostgreSQL
ALTER TABLE employees ALTER COLUMN email SET NOT NULL;

-- ④ DEFAULT も同時に設定しておくと今後の INSERT で NULL が入らなくなる
ALTER TABLE employees MODIFY COLUMN email VARCHAR(200) NOT NULL DEFAULT '';
-- または: ALTER TABLE employees MODIFY COLUMN status VARCHAR(20) NOT NULL DEFAULT 'active';

よくある質問(FAQ)

QALTER TABLE の実行中にアプリが止まりますか?
A操作の種類とテーブルサイズによります。MySQL 8.0 の ADD COLUMNALGORITHM=INSTANT で即座に完了しロックが発生しません。しかし MODIFY COLUMN(型変更)は内部でテーブル全体をコピーするため、数百万行のテーブルでは数分〜数十分かかりその間ロックが発生します。本番環境では事前にステージングで実行時間を確認し、必要に応じて pt-osc や gh-ost を使ってください。
Q列の順序を変えることはできますか?
AMySQL では ADD COLUMN ... AFTER 列名 / FIRST で追加位置を指定できます。ただし既存の列の順序を並び替える操作はどの RDBMS も標準的な方法はなく、テーブルを新規作成して INSERT INTO ... SELECT でデータを移行する方法が一般的です。実務では「列の並び順」を気にするより SELECT 時に必要な列を明示する設計のほうが重要です。
QALTER TABLE はトランザクションに含められますか?
APostgreSQL では DDL がトランザクションに含められ、ROLLBACK でキャンセルできます。MySQL(InnoDB)では DDL を実行すると暗黙的に COMMIT が走るため、BEGIN; ALTER TABLE …; ROLLBACK; としても ROLLBACK できません。SQL Server は ROLLBACK 可能です(バージョンにより異なります)。
Q列を追加したら既存の行の値はどうなりますか?
A追加した列に DEFAULT 値 を指定している場合はその値が既存行に設定されます。DEFAULT を指定しなかった場合は NULL が設定されます(NOT NULL 制約がある場合はエラー)。MySQL 8.0 の INSTANT 追加では実際には行を更新せず、デフォルト値はメタデータに記録されて SELECT 時に返します(物理行は変更されません)。
Q外部キーを後から追加しようとするとエラーになります。どう対処しますか?
A外部キーを追加しようとするテーブルに、参照先テーブルに存在しない値(孤立データ)が含まれているとエラーになります。先に SELECT ... WHERE dept_id NOT IN (SELECT dept_id FROM departments) のような SQL で孤立データを確認・修正してから外部キーを追加してください。一時的に外部キーチェックを無効化して追加することもできますが、データ品質の問題を後回しにするためお勧めしません。

まとめ

ALTER TABLE の操作パターンを一覧表でまとめます。

操作 MySQL PostgreSQL SQL Server
列の追加 ADD COLUMN 名 型 [FIRST|AFTER 列] ADD COLUMN 名 型 ADD 名 型
列の削除 DROP COLUMN 名 DROP COLUMN [IF EXISTS] 名 DROP COLUMN 名
型・サイズ変更 MODIFY COLUMN 名 新型 ALTER COLUMN 名 TYPE 新型 [USING] ALTER COLUMN 名 新型
列名変更 RENAME COLUMN 旧 TO 新(8.0+) RENAME COLUMN 旧 TO 新 EXEC sp_rename 'tbl.旧', '新', 'COLUMN'
テーブル名変更 RENAME TO 新名 RENAME TO 新名 EXEC sp_rename '旧', '新'
NOT NULL 追加 MODIFY COLUMN 名 型 NOT NULL ALTER COLUMN 名 SET NOT NULL ALTER COLUMN 名 型 NOT NULL
DEFAULT 追加 MODIFY COLUMN 名 型 DEFAULT 値 ALTER COLUMN 名 SET DEFAULT 値 ADD CONSTRAINT df名 DEFAULT 値 FOR 名
UNIQUE 追加 ADD CONSTRAINT 制約名 UNIQUE (列名)(共通)
外部キー追加 ADD CONSTRAINT 制約名 FOREIGN KEY (列) REFERENCES 親(列)(共通)

本番環境では ALTER TABLE を実行する前に必ずテーブルサイズとロックの影響を確認し、大量テーブルには Online DDL(ALGORITHM=INSTANT/INPLACE)やpt-online-schema-change・gh-ost の活用を検討してください。

テーブルの削除はDROP TABLE の完全ガイドを、プライマリーキーの操作はプライマリーキーの追加と削除を参照してください。