ALTER TABLE で構造を変更する
ALTER TABLE で構造を変更する とは
ALTER TABLEを使ってテーブルの構造を変更する方法を学びます。カラムの追加や変更を実践!。本レッスンでは、ALTER TABLE で構造を変更する の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
なぜ重要か
プロダクトが成長するにつれ、テーブル設計は必ず変化を求められます。新しい列を追加したい、既存列の型を変えたい、要らなくなった列を削除したい、こうした「すでに動いているテーブルの形を変える」命令が ALTER TABLE です。アプリ開発者にとっては「マイグレーションを書く」という言葉で日常的に出会う命令でもあります。大規模なテーブルで何も考えずに ALTER を流すと、テーブルが長時間ロックされて全リクエストが詰まる事故になります。ALTER は「動いている車のエンジンを交換する」のに近い操作で、必要性と運用上のリスクの両方を理解しておく必要があります。
主なバリエーション
SQL クエリ
-- 列を追加
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
-- 列を削除
ALTER TABLE users DROP COLUMN phone;
-- 列の型を変える
ALTER TABLE users ALTER COLUMN age TYPE BIGINT;
-- 列名を変える
ALTER TABLE users RENAME COLUMN name TO display_name;
-- NOT NULL 制約を追加する
ALTER TABLE users ALTER COLUMN display_name SET NOT NULL;
-- インデックスを追加
CREATE INDEX idx_users_email ON users (email);列追加の流れ
NOT NULL の列を追加する場合は、既存行が無いか、または DEFAULT を必ず指定します。大量の既存データに DEFAULT を流し込むと書き込み量が大きくなり、本番では「2 段階デプロイ」 (まず NULL 許容で追加 → アプリで値を埋める → NOT NULL 化) という運用がよく使われます。
代表例 — 顧客テーブルに会員ランク列を追加
SQL クエリ
-- 既存テーブルがあるとする
-- CREATE TABLE customers (id INT PRIMARY KEY, name VARCHAR(100));
-- 1. ランク列を追加 (NULL 許容で気軽に追加)
ALTER TABLE customers ADD COLUMN rank VARCHAR(20);
-- 2. 既存データに値を埋める
UPDATE customers SET rank = 'bronze' WHERE rank IS NULL;
-- 3. NOT NULL 化して締める
ALTER TABLE customers ALTER COLUMN rank SET NOT NULL;3 段階に分けることで、本番ロックを最小化できます。
列を消す前に必ず確認
本番で列を消すと、その列を参照しているクエリが一斉に壊れます。
SQL クエリ
-- アプリのコードと SQL を grep して参照ゼロを確認してから
ALTER TABLE customers DROP COLUMN legacy_flag;注意 ALTER TABLE は「すぐ終わる軽い操作」と思いがちですが、PostgreSQL でも操作内容によってはテーブル全行の検証や書き換えが発生する重い処理になります。1000 万行のテーブルに ALTER を流して 30 分ロック、というのは現場でよく起こります。本番では
ONLINEオプションやpt-online-schema-changeなどの仕組みを検討します。
アプリの世界では ALTER TABLE を生で書くより、
drizzle-kitやprisma migrateのようなマイグレーションツール経由で生成・適用するのが主流です。ツールが自動生成する SQL をレビューできる目を持つことが、結局のところ ALTER TABLE を読み書きできることに繋がります。
本番マイグレーションで列を「リネーム」したい時は、直接 RENAME COLUMN で名前を変えない方が安全です。理由は「旧列で動いている古いアプリと、新列を期待する新しいアプリ」が同時に走るタイミングがあるからです。代わりに、新列を追加 → 両方に書く → 旧列の参照を消す → 旧列を消す、という 4 段階のデプロイが鉄則です。
インデックス追加と削除
インデックスも ALTER TABLE で足したり消したりできます。
SQL クエリ
-- email に検索高速化用のインデックスを追加
CREATE INDEX idx_users_email ON users (email);
-- 使われていないインデックスを削除
DROP INDEX idx_users_email;インデックスの細かい話は最終章で扱いますが、ALTER の構文の一部として頭に入れておくと、本番のマイグレーションログを読めるようになります。
まとめ
- ADD / DROP / ALTER COLUMN / RENAME COLUMN / CREATE INDEX が構造変更の主な顔ぶれ
- 列追加は NULL 許容 → データ埋め → NOT NULL 化の 3 段階が安全
- 列削除はアプリ参照ゼロを確認してから
- リネームは「新列追加 → 両書き → 旧列消し」の 4 段階デプロイ
- 本番大規模テーブルは長時間ロックの可能性、ONLINE 系の仕組みを検討する
次のレッスン
次は 制約 (NOT NULL / UNIQUE / DEFAULT) です。NOT NULL、UNIQUE、DEFAULT制約をSQLで設定する方法を実践的に学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- ALTER TABLE の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. ALTER TABLE とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
テーブル構造
schema.sql
CREATE TABLE customers (
id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
INSERT INTO customers (id, name) VALUES
(1, '田中太郎'),
(2, '佐藤花子'),
(3, '山田次郎');期待される出力
| id | name | member_rank |
|---|---|---|
| 1 | 田中太郎 | bronze |
| 2 | 佐藤花子 | bronze |
| 3 | 山田次郎 | bronze |