MySQL 入門

MySQLのテーブル構造を変更する (ALTER TABLE)

データベースのテーブル構造は、一度決めたら不変というわけではありません。ビジネスの成長に伴い、新しいデータ要件への対応や既存設計の最適化のために、スキーマ(Schema)を進化させる必要が頻繁に生じます。MySQLはテーブル構造を変更するための強力なコマンドを提供しており、テーブル作成後でもカラムの追加、変更、削除が可能です。

これらの操作はすべて ALTER TABLE ステートメントを使用して行われます。これはデータ定義言語(DDL)における非常に核心的なコマンドです。

1. カラムの追加

テーブルに追加の属性を保存する必要がある場合、新しいカラムの追加は最も一般的な要求です。これは ALTER TABLE ... ADD COLUMN ステートメントを使用して実現します。カラムを追加する際は、カラム名、データ型、および制約(Constraints)を指定します。これは最初にテーブルを作成する際の手順と非常によく似ています。

1.1 カラム追加の構文

ALTER TABLE table_name
ADD COLUMN column_name DATATYPE [column_constraint];
  • table_name: 変更対象のテーブル名。
  • column_name: 追加する新しいカラムの名前。
  • DATATYPE: 新しいカラムのデータ型(例: VARCHAR(255), INT, DECIMAL(10,2))。データ型の選択はデータの整合性とパフォーマンスに直結します。
  • column_constraint: オプションの制約条件。NOT NULLDEFAULT(デフォルト値)、UNIQUE(ユニーク制約)、または新カラムの挿入位置を指定する AFTER 既存カラム名 / FIRST など。

1.2 カラム追加のコード例

例として、customer_idfirst_namelast_name のみを保持する Customers テーブルがあると仮定します。

-- 初期の Customers テーブル構造
CREATE TABLE Customers (
    customer_id INT PRIMARY KEY AUTO_INCREMENT,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL
);

基本的なカラム追加

各顧客のメールアドレスを保存する必要があるとします。

ALTER TABLE Customers
ADD COLUMN email VARCHAR(100) UNIQUE;

このコマンドは VARCHAR(100) 型の email カラムを追加します。UNIQUE 制約により、重複するメールアドレスは許可されません。NOT NULL を指定していないため、既存のデータ行には NULL が挿入され、新規データでメールアドレスが提供されない場合もデフォルトで NULL となります。

デフォルト値を持つカラムの追加

顧客アカウントの作成日時を追跡したい場合を考えます。

ALTER TABLE Customers
ADD COLUMN registration_date DATE DEFAULT (CURRENT_DATE);

これにより DATE 型の registration_date カラムが追加されます。DEFAULT (CURRENT_DATE) は、INSERT 時に値が提供されない場合、MySQLが自動的に現在の日付を挿入することを意味します。重要: テーブルに既に存在する履歴データには、実際の登録日ではなく、この ALTER TABLE 操作を実行した日の日付が初期値として設定されます。

NOT NULL カラムの追加

新しいカラムに必ず値が必要な場合(ステータスフィールドなど)で、即座にルールを適用したい場合:

ALTER TABLE Customers
ADD COLUMN customer_status VARCHAR(20) NOT NULL DEFAULT 'Active';

ここでは customer_statusVARCHAR(20) として追加され、NOT NULL 制約が付与されています。既存のデータに対応するため、DEFAULT 'Active' を提供する必要があります。このデフォルト値がない場合、既存の行が NOT NULL の要件を満たせないため、ALTER TABLE ステートメントはエラーとなり失敗します。

カラムの挿入位置の指定

FIRST(先頭)または AFTER 既存カラム名 を使用して、カラムの並び順を制御できます。

ALTER TABLE Customers
ADD COLUMN phone_number VARCHAR(20) AFTER last_name;

これにより phone_numberlast_name カラムの直後に追加されます。

ALTER TABLE Customers
ADD COLUMN customer_priority INT DEFAULT 0 FIRST;

これにより customer_priority がテーブルの最初のカラムとして追加されます。MySQLにおいて列の順序は通常、機能やクエリのパフォーマンスに影響しませんが、MySQL Workbench などのツールでデータを確認する際の可読性が向上します。

2. 既存カラムの変更

カラム作成後、その属性を調整する必要があるかもしれません。データ型、制約(NOT NULLDEFAULT)、さらにはカラム名自体を変更できます。これには ALTER TABLE ... MODIFY COLUMN または ALTER TABLE ... CHANGE COLUMN を使用します。

2.1 カラム変更の構文

  • MODIFY COLUMN: カラム名を変えずに、定義(データ型や制約)のみを変更する場合に使用します。
ALTER TABLE table_name
MODIFY COLUMN column_name DATATYPE [column_constraint];

CHANGE COLUMN: 定義と同時にカラム名も変更する場合に使用します。旧カラム名と新カラム名の両方を記述する必要があります。

ALTER TABLE table_name
CHANGE COLUMN old_column_name new_column_name DATATYPE [column_constraint];

2.2 カラム変更のコード例

拡張後の Customers テーブルを引き続き使用します。

データ型と制約の変更(MODIFY を使用)

当初 emailVARCHAR(100) UNIQUE でしたが、100文字を超えるアドレスに対応する必要が生じ、さらに NOT NULL を必須とすることにします。

ALTER TABLE Customers
MODIFY COLUMN email VARCHAR(255) UNIQUE NOT NULL;

このコマンドで email の長さが 255 に拡張され、NOT NULL 制約が付与されます。注意: 変更前にテーブル内に emailNULL のデータが存在する場合、このステートメントは失敗します。先に UPDATE 文で空のデータを埋めてから実行する必要があります。

カラム名の変更(CHANGE を使用)

意味をより明確にするため、customer_statusaccount_status に変更します。

ALTER TABLE Customers
CHANGE COLUMN customer_status account_status VARCHAR(20) NOT NULL DEFAULT 'Active';

ここではカラム名が変更されています。重要: 名前だけを変更したい場合でも、データ型とすべての制約を完全に書き直す必要があります。記述を省略すると、そのカラムの以前の定義は失われます。

デフォルト値 (DEFAULT) の変更

デフォルトの優先度を 0 から 1 に変更する場合:

ALTER TABLE Customers
ALTER COLUMN customer_priority SET DEFAULT 1;

これは今後挿入される新しいデータにのみ影響し、既存データの値は保持されます。

デフォルト値の削除

特定のカラムにデフォルト値が不要になった場合:

ALTER TABLE Customers
ALTER COLUMN registration_date DROP DEFAULT;

デフォルト値を削除した後、INSERT 時に日付が提供されない場合、NOT NULL ならエラーになり、そうでなければ NULL が格納されます。

2.3 カラム変更時の注意点

  • データ消失のリスク: データ型をより緩やかなものに変更する(例: INT から BIGINTVARCHAR(10) から VARCHAR(100))のは通常安全です。しかし、より厳しい型への変更(例: VARCHAR(100) から VARCHAR(10))は、データの切り捨てやエラーを引き起こす可能性があります。操作前には必ずバックアップを取得してください。
  • パフォーマンスへの影響: 巨大なテーブルに対する ALTER TABLE は非常に時間がかかり、テーブルがロックされるため、その間アプリケーションが応答できなくなることがあります。MySQL 8.0以降では多くのシナリオでオンラインDDL(Online DDL)がサポートされていますが、本番環境では慎重な計画が必要です。
  • 依存関係: カラムがインデックス、外部キー(Foreign Key)、またはビューの一部として使用されている場合、変更がそれらの関連オブジェクトに影響を与える可能性があります。

3. カラムの削除

特定のカラムが不要になったことが確実な場合、ALTER TABLE ... DROP COLUMN を使用して削除できます。これは破壊的な操作であり、そのカラム内のすべてのデータが永久に削除されます。

3.1 カラム削除の構文

ALTER TABLE table_name
DROP COLUMN column_name;

3.2 カラム削除のコード例

基本的な削除

電話番号カラムが不要になった場合:

ALTER TABLE Customers
DROP COLUMN phone_number;

依存関係のあるカラムの削除

カラムが外部キー制約によって参照されている場合は、通常先に外部キーを削除する必要があります。インデックスが存在する場合、MySQLは通常自動的に削除しますが、複雑な構成では手動でインデックスを削除する必要がある場合もあります。

-- 'email' に 'idx_email' という名前のインデックスがあると仮定
-- 自動処理されない場合は先に以下を実行:
-- ALTER TABLE Customers DROP INDEX idx_email;

ALTER TABLE Customers
DROP COLUMN email;

3.3 カラム削除時の注意点

  • 不可逆なデータ消失: カラム削除後、中のデータは永久に失われます。
  • アプリケーションへの影響: バックエンドのコードが削除されたカラムに対してSQLクエリを実行し続けている場合、アプリケーションはクラッシュします。リリース前に必ず開発チームと調整を行ってください。

4. 総合的な実践演習

Products(製品)テーブルのシナリオを通じて、知識を定着させましょう。

初期のテーブル作成とデータ挿入

CREATE TABLE Products (
    product_id INT PRIMARY KEY AUTO_INCREMENT,
    product_name VARCHAR(100) NOT NULL,
    price DECIMAL(10, 2) NOT NULL,
    stock_quantity INT NOT NULL DEFAULT 0
);

INSERT INTO Products (product_name, price, stock_quantity) 
VALUES ('Laptop', 1200.00, 50), ('Mouse', 25.50, 200), ('Keyboard', 75.00, 100);

SELECT * FROM Products;

出力結果:

+------------+--------------+---------+----------------+
| product_id | product_name | price   | stock_quantity |
+------------+--------------+---------+----------------+
|          1 | Laptop       | 1200.00 |             50 |
|          2 | Mouse        |   25.50 |            200 |
|          3 | Keyboard     |   75.00 |            100 |
+------------+--------------+---------+----------------+

シナリオ 1:説明カラムの追加 (NULL 許可)

ALTER TABLE Products
ADD COLUMN description TEXT;

SELECT product_id, product_name, description FROM Products;

既存データの descriptionNULL になります。

シナリオ 2:NOT NULL でデフォルト値を持つカラムの追加

is_available(販売中かどうか)フラグを追加します。

ALTER TABLE Products
ADD COLUMN is_available BOOLEAN NOT NULL DEFAULT TRUE;

SELECT product_id, product_name, is_available FROM Products;

既存データには自動的に TRUE(1) が割り当てられます。
(※MySQLでは BOOLEAN の実体は TINYINT(1) であり、1がTRUE、0がFALSEを表します。)

シナリオ 3:データ型の変更 (MODIFY)

製品名のフィールドが短すぎるため、255文字に拡張します。

ALTER TABLE Products
MODIFY COLUMN product_name VARCHAR(255) NOT NULL;

シナリオ 4:カラム名の変更 (CHANGE)

stock_quantity をより正確な current_stock に変更します。

ALTER TABLE Products
CHANGE COLUMN stock_quantity current_stock INT NOT NULL DEFAULT 0;

シナリオ 5:カラムの削除 (DROP)

description カラムが不要になったため削除します。

ALTER TABLE Products
DROP COLUMN description;