11.4.4 ENUM 型

ENUM は、テーブル作成時にカラム仕様に明示的に列挙された、許可されている値のリストから選択された値を持つ文字列オブジェクトです。これには次の利点があります。

  • 指定可能な値のセットがカラムで制限されている状況でのコンパクトなデータストレージ。入力値として指定した文字列は自動的に数値としてエンコードされます。ENUM 型のストレージ要件については、セクション11.7「データ型のストレージ要件」を参照してください。

  • 読みやすいクエリーと出力。数値は、クエリー結果で対応する文字列に戻されます。

また、次のような考慮が必要な問題が生じる可能性があります。

  • Enumeration Limitationsで説明しているように、数値のように見える列挙値を作成した場合、リテラル値とその内部インデックス番号を混同しやすくなります。

  • Enumeration Sortingで説明しているように、ORDER BY 句で ENUM カラムを使用するには特に注意が必要です。

ENUM カラムの作成と使用

列挙値は引用符で囲んだ文字列リテラルにする必要があります。たとえば、次のように ENUM カラムを持つテーブルを作成できます。

CREATE TABLE shirts (
    name VARCHAR(40),
    size ENUM('x-small', 'small', 'medium', 'large', 'x-large')
);
INSERT INTO shirts (name, size) VALUES ('dress shirt','large'), ('t-shirt','medium'),
  ('polo shirt','small');
SELECT name, size FROM shirts WHERE size = 'medium';
+---------+--------+
| name    | size   |
+---------+--------+
| t-shirt | medium |
+---------+--------+
UPDATE shirts SET size = 'small' WHERE size = 'large';
COMMIT;

'medium' の値を持つ 100 万個の行をこのテーブルに挿入するには、100 万バイトのストレージが必要ですが、実際の文字列 'medium'VARCHAR カラムに格納した場合は、600 万バイト必要になります。

列挙リテラルのインデックス値

それぞれの列挙値にはインデックスが設定されています。

  • カラム仕様にリストされている要素には、1 から始まるインデックス番号が割り当てられています。

  • 空の文字列エラー値のインデックス値は 0 です。つまり、次の SELECT ステートメントを使用して、無効な ENUM 値が割り当てられた行を検索できます。

    mysql> SELECT * FROM tbl_name WHERE enum_col=0;
    
  • NULL 値のインデックスは NULL です。

  • ここでのインデックスという語は、列挙値のリスト内での位置を示します。これは、テーブルインデックスとはまったく関係ありません。

たとえば、ENUM('Mercury', 'Venus', 'Earth') と指定されたカラムには、次に示すどの値でも含めることができます。それぞれの値のインデックスも示しています。

インデックス
NULL NULL
'' 0
'Mercury' 1
'Venus' 2
'Earth' 3

ENUM カラムには、最大 65,535 個の個別の要素を含めることができます。(実用的な限度は 3000 個までです。)テーブルには、グループと見なされる ENUM および SET カラムの中の一意の要素リスト定義を、255 個以下を含めることができます。これらの制限の詳細は、セクションD.10.5「.frm ファイル構造により課せられる制限」を参照してください。

ENUM 値を数値コンテキストで取得した場合、カラム値のインデックスが返されます。たとえば、次のように ENUM カラムから数値を取得できます。

mysql> SELECT enum_col+0 FROM tbl_name;

数値引数を取る SUM()AVG() などの関数は、必要に応じて引数を数値にキャストします。ENUM 値の計算にはインデックス番号が使用されます。

列挙リテラルの処理

テーブルが作成されるときに、テーブル定義内の ENUM メンバー値から末尾のスペースが自動的に削除されます。

ENUM カラムに格納された値は、取得されたときに、カラム定義で使用された大文字/小文字で表示されます。ENUM カラムには文字セットと照合順序を割り当てられています。バイナリ照合順序、または大文字と小文字を区別する照合順序の場合、カラムに値を割り当てるときに、大文字/小文字が考慮されます。

ENUM カラムに数字を格納すると、その数字は指定可能な値のインデックスとして扱われ、格納された値がそのインデックスを持つ列挙メンバーとなります。(ただし、これはすべての入力を文字列として扱う LOAD DATA では機能 しません。)数値が引用符で囲まれている場合、列挙値のリストに一致する文字列がなければ、そのままインデックスとして解釈されます。これらの理由により、ENUM カラムを数字のように見える列挙値で定義することは、混乱を招きやすくなるのでお勧めできません。たとえば、次のカラムには '0''1'、および '2' の文字列値を持つ列挙メンバーが指定されていますが、数値インデックス値は 12、および 3 です。

numbers ENUM('0','1','2')

2 を格納すると、それはインデックス値と解釈され、'1' (インデックス 2 の値) になります。'2' を格納すると、それは列挙値と一致するので、'2' として格納されます。'3' を格納すると、どの列挙値とも一致しないのでインデックスとして扱われ、'2' (インデックス 3 の値) になります。

mysql> INSERT INTO t (numbers) VALUES(2),('2'),('3');
mysql> SELECT * FROM t;
+---------+
| numbers |
+---------+
| 1       |
| 2       |
| 2       |
+---------+

ENUM カラムのすべての指定可能な値を特定するには、SHOW COLUMNS FROM tbl_name LIKE 'enum_col' を使用して、出力の Type カラム内の ENUM 定義を構文解析します。

C API では、ENUM 値は文字列として返されます。結果セットのメタデータを使用してこれらをほかの文字列から区別する方法については、セクション23.8.5「C API データ構造」を参照してください。

空または NULL の列挙値

以下のような特定の状況下では、列挙値は、空の文字列 ('') や NULL になることもあります。

  • ENUM に無効な値 (つまり、許可された値のリストに存在しない文字列) を挿入すると、特殊なエラー値として空の文字列が代わりに挿入されます。この文字列は、この文字列に 0 の数値が含まれていることで、通常の空の文字列と区別できます。列挙値の数値インデックスの詳細は、Index Values for Enumeration Literalsを参照してください。

    厳密な SQL モードが有効な場合は、無効な ENUM 値を挿入しようとするとエラーが発生します。

  • ENUM カラムが NULL を許可するように宣言されている場合、NULL 値は、そのカラムに対して有効な値であり、デフォルト値は NULL になります。ENUM カラムが NOT NULL として宣言されている場合、デフォルト値は許可されている値のリストの最初の要素になります。

列挙のソート

ENUM 値は、インデックス番号に基づいてソートされますが、この数値は、カラム仕様で列挙メンバーがリストされていた順序に従います。たとえば、ENUM('b', 'a') の場合、'b''a' の前にソートされます。空の文字列は空ではない文字列の前にソートされ、NULL 値はその他のすべての列挙値の前にソートされます。

ENUM カラムで ORDER BY 句の使用時に予想外の結果になることを回避するには、次のいずれかの手法を使用します。

  • アルファベット順で ENUM リストを指定します。

  • ORDER BY CAST(col AS CHAR) または ORDER BY CONCAT(col) をコード化することにより、カラムがインデックス番号ではなく、辞書順でソートされることを確認します。

列挙の制限

列挙値は、文字列値に評価されるものであっても、式にはできません。

たとえば、次の CREATE TABLE ステートメントは、CONCAT 関数を列挙値の構築に使用できないので、機能しません

CREATE TABLE sizes (
    size ENUM('small', CONCAT('med','ium'), 'large')
);

ユーザー変数を列挙値として使用することもできません。次のステートメントのペアは機能しません

SET @mysize = 'medium';

CREATE TABLE sizes (
    size ENUM('small', @mysize, 'large')
);

数字を列挙値として使用しないことを強くお勧めします。これは、適切な TINYINT または SMALLINT 型よりもストレージを節約するわけでもなく、ENUM 値を間違って引用符で囲んだ場合には、文字列とベースになる数値とを混同しやすくなる (同じでない場合もあります) からです。数字を列挙値として使用する場合は、必ず引用符で囲んでください。引用符を省略した場合は、その数字はインデックスと見なされます。Handling of Enumeration Literalsを参照して、引用符で囲まれた数字でも間違って数字のインデックス値として使用されるか場合について確認してください。

定義の中に重複した値が含まれていると、警告 (厳密な SQL モードが有効になっている場合はエラー) が発生します。


User Comments
  Posted by Bradford Henderson on April 28, 2011
Can the enum type refer directly to a table? For example, a table (streets) with 2 cols - streetID and streetName. An example would be helpful if it showed the statement used to create the enum column and then an example statement to utilize the column.
  Posted by Tim Bancroft on April 29, 2011
@Brad: What you're looking for - referential integrity - is probably best enforced by the REFERENCE or FOREIGN KEY features in SQL which isn't fully supported in most implementations of 5.1 (at least, possibly other releases, too) (See Create TABLE http://dev.mysql.com/doc/refman/5.1/en/create-table.html). A TRIGGER may work, depending on what you want to do (see CREATE TRIGGER http://dev.mysql.com/doc/refman/5.1/en/create-trigger.html) which can reference other tables by name.

When using the returned values, you reference them as a text string, unless you use the (0+<enum_col>) format above, which would return the index as an integer.

e.g SELECT <enum_col> FROM foo INTO var WHERE...
IF <enum_col> = 'enum_string_value' THEN....

So if the column is defined in the CREATE TABLE with
<enum_col> ENUM('ValueA', 'StreetB', 'CityC', ...)
it will return 'ValueA', 'StreetB' ... and so on in normal use.

Hope this helps.

***Mods - finger slipped - possible duplicate post ***
Sign Up Login You must be logged in to post a comment.