MySQL の ENUM 型と SET 型

ENUM 型と SET 型は、カラムに格納できる値をあらかじめ定義したリストに制限する MySQL 固有のデータ型です。便利な反面、運用上の注意点も多いため、特性を理解した上で使う必要があります。

ENUM 型の基本

ENUM はリストの中から1つだけ値を選ぶ型です。内部的には整数(1, 2, 3…)で格納されるため、VARCHAR に比べてストレージ効率がよくなります。

CREATE TABLE tickets (
  id INT AUTO_INCREMENT PRIMARY KEY,
  title VARCHAR(200) NOT NULL,
  priority ENUM('low', 'medium', 'high', 'critical') NOT NULL DEFAULT 'medium'
);

-- 定義済みの値のみ挿入可能
INSERT INTO tickets (title, priority) VALUES ('バグ修正', 'high');

-- 定義外の値はエラー(strict モード時)
INSERT INTO tickets (title, priority) VALUES ('機能追加', 'urgent');
-- ERROR: Data truncated for column 'priority'

SET 型の基本

SET は ENUM と似ていますが、リストの中から複数の値を選べる点が異なります。内部的にはビットマスクで格納されます。

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  hobbies SET('reading', 'gaming', 'cooking', 'sports') NOT NULL
);

-- 複数の値をカンマ区切りで指定
INSERT INTO users (name, hobbies) VALUES ('Alice', 'reading,cooking');
INSERT INTO users (name, hobbies) VALUES ('Bob', 'gaming');

ENUM と SET の違い

ENUM

リストから1つだけ選択。ストレージは1〜2バイト。最大65,535個の値を定義可能。ORDER BY でインデックス順(定義順)にソートされる。

SET

リストから複数選択可。ストレージは1〜8バイト。最大64個の値を定義可能。FIND_IN_SET() 関数で検索する。

ENUM 型の注意点

ENUM は一見便利ですが、運用上の落とし穴があります。

値の追加・変更に ALTER TABLE が必要

新しい選択肢を追加するには ALTER TABLE でカラム定義を変更する必要があります。テーブルが大きいと、この操作に時間がかかる可能性があります。

ソート順が定義順になる

ENUM の ORDER BY はアルファベット順ではなく、定義した順番で並びます。これを知らないと予期しないソート結果になります。

数値との混同

ENUM は内部的に整数ですが、数値文字列を ENUM 値にすると混乱の原因になります。ENUM(‘0’, ‘1’, ‘2’) のような定義は避けるべきです。

ENUM の代替手段

ENUM の制約が問題になる場合は、参照テーブルを作って外部キーで結ぶ方法が代替案になります。

-- 参照テーブル方式
CREATE TABLE priorities (
  id TINYINT PRIMARY KEY,
  name VARCHAR(20) NOT NULL UNIQUE
);

INSERT INTO priorities VALUES (1, 'low'), (2, 'medium'), (3, 'high'), (4, 'critical');

CREATE TABLE tickets (
  id INT AUTO_INCREMENT PRIMARY KEY,
  title VARCHAR(200) NOT NULL,
  priority_id TINYINT NOT NULL DEFAULT 2,
  FOREIGN KEY (priority_id) REFERENCES priorities(id)
);

この方式なら値の追加は INSERT だけで済み、ALTER TABLE が不要です。また、優先度に表示名や表示色などの属性を持たせたくなった場合にも、参照テーブルにカラムを追加するだけで対応できます。

どちらを選ぶか

値が今後ほぼ変わらず、選択肢が少ない場合(性別、曜日など)は ENUM で十分です。値の追加・変更が予想される場合や、選択肢に属性を持たせたい場合は参照テーブル方式が適しています。SET 型は多対多リレーションの簡易版と考えられますが、正規化の観点からは中間テーブルを使うほうが正統的な設計です。