sql >> データベース >  >> RDS >> Mysql

MySQLのENUM(列挙)データ型:トップ12の事実と役立つヒント

    MySQL ENUMデータは、許可された値のリストから選択された値を持つ文字列データ型です。以下に示すように、テーブルの作成中にこれらの許可された値を設定します。

    CREATE TABLE Product
    (
        id int NOT NULL PRIMARY KEY,
        productName varchar(30) NOT NULL,
        color enum('blue','red','yellow','black','white') NOT NULL DEFAULT 'blue'
    );
    

    簡単ですね。

    手始めに、データ検証は別のテーブルと外部キーなしで即座に行われます。厳密なサーバーモードでは、これは間違ったエントリを強制できないことを意味します。これは素晴らしいです!

    それともそうですか?

    世界の他の物と同じように、それがいつまでも幸せであるとは限りません。

    MySQL ENUMに関する次の12の重要な事実を読んだ後、MySQLの次のデータベースまたはテーブルに適しているかどうかを判断できます。

    この記事では、MySQLのバージョンは8.0.23であり、ストレージエンジンはInnoDBです。

    1。 MySQLENUMはキー/文字列値のペアタイプです

    MySQLENUMはキーと値のペアです。値は文字列であり、キーはインデックス番号です。

    しかし、インデックスはどこにありますか?

    MySQLは、リストに表示されている番号を自動的に割り当てます。そのため、色、顧客の種類、敬礼、支払い方法のいずれであっても、番号が割り当てられます。それは決して拡大しない固定リストです。それ以上の属性を持つことのない20以下のアイテムと値を考えてください。それ以外の場合は、テーブルが必要です。

    しかし、これらのインデックスにはどのように番号が付けられていますか?

    2。 MySQL ENUMインデックスは1で始まりますが、NULLまたはゼロにすることができます

    例から始めましょう。

    CREATE TABLE people
    (
      id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
      lastname varchar(30) NOT NULL,
      firstname varchar(30) NOT NULL,
      middlename varchar(30) NOT NULL,
      gender enum('Male','Female') NOT NULL DEFAULT 'Female',
      country enum('United States', 'Canada', 'Brazil', 
                   'United Kingdom','Poland','Ukraine', 'Lithuania',  
                   'Japan','Philippines','Thailand', 'Australia','New Zealand')  
                  DEFAULT 'United States',
      modifieddate datetime NOT NULL DEFAULT NOW() 
    );
    

    ここには2つのMySQLENUM値があります:性別 および性別から始めましょう 2つの値を含む列:男性 および女性男性のインデックス は1で、女性 は2です。これは、キーインデックスが1で始まることを意味します。

    この簡単な例から、のインデックスを特定できます。 桁。 12個の値があります。インデックスが1の米国で始まり、インデックスが12のニュージーランドで終わります。

    :このインデックスは、高速検索に使用するテーブルインデックスを参照していません。

    1から65,535までのこれらの数値に加えて、ENUM列はNULLまたはゼロにすることもできます。この例では、 列はNULLを受け入れます。したがって、インデックス1から12を除いて、NULLはNULL値を持つ別の可能なインデックスです。

    インデックスを0にすることもできます。これは、次の状況で発生します。

    • MySQLのサーバーモードは厳密ではありません。
    • 許可された値のリストにない値を挿入しました。
    • その後、挿入は成功しますが、値はインデックスがゼロの空の文字列です。

    エラーを回避するには、常に厳密なサーバーモードを使用してください。

    3。 MySQLENUMは列に可能な値を制限します

    厳密モードでは、 前の例の列は、12個の可能な値のみを受け入れます。したがって、これを実行しようとすると、「列「国」のデータが切り捨てられました」というエラーがスローされます。

    INSERT INTO people (lastname, firstname, middlename, gender, country)
      VALUES ('Choi', 'Seungcheol', '','Male','South Korea');
    

    以下のエラーメッセージは、韓国が列挙リストに含まれていないために発生しました。

    エラーメッセージはMySQLWorkbenchの場合と同じです。

    ここで使用されているMySQLサーバーで大文字と小文字が区別される場合、これも受け入れられません。

    INSERT INTO people (lastname, firstname, middlename, gender, country)
      VALUES ('Hemsworth', 'Chris', '', 'MALE', 'united states');
    

    なんで?性別を男性と定義しました 、 MALEではありません 。そして国は米国です 、米国ではありません。

    最終的に、MySQL ENUMデータ型の列挙値は外部キー制約のように機能しますが、別のテーブルはありません。

    これとは別に、MySQLENUMデータが提供するもう1つの利点があります。

    4。 JOINを使用しないフレンドリーな出力

    JOINは必要ありませんが、出力はわかりやすくなっています。以下のMySQLの例でENUMを取り上げて説明しましょう:

    SELECT * FROM people 
    WHERE country = 4;

    このクエリは、英国から人々を取得します。デフォルトでは、ENUM列に定義した文字列が表示されます。ただし、内部的には、番号付きのインデックスが格納されます。結果は次のとおりです。

    表示されるデータはを使用して生成されたものです dbForge StudioforMySQLのデータ生成ツール。 ツールを使用して50,000個の名前を生成しました。

    一方、別のテーブルと結合を使用した場合も同じ出力を実現できます。

    SELECT
     p.id
    ,p.lastname
    ,p.firstname
    ,p.middlename
    ,CASE WHEN p.gender = 'M' THEN 'Male' ELSE 'Female' END AS gender
    ,c.countryname AS country
    ,p.modifieddate
    FROM people_no_enums p
    LEFT JOIN country c ON p.country = c.id
    WHERE p.country = 4;
    

    では、JOINを完全に回避するためにMySQL ENUMを使用する必要がありますか? 絶対にありません!これは、小さいが固定されたリストに適しています。行数が不定で属性が多いデータが増えると、テーブルが必要になります。また、図2のようにわかりやすい出力を作成するには、JOINも必要です。別のテーブルを持つことはより柔軟であり、データがライブであるときに開発者から何も必要としません。これは、Enumdatatypeには当てはまりません。

    5。 MySQL列挙型をインデックスまたは文字列値でフィルタリングする

    ポイント4では、ENUM列でフィルタリングするWHERE句の例を見ました。国を指定するためにインデックスを使用しました。したがって、これも機能します:

    SELECT * from people
    WHERE country IN (1,3,5)
    AND gender = 1;

    次のような文字列値を使用することもできます:

    SELECT * FROM people 
    WHERE country='Philippines'
    AND gender = 'Female';

    6。並べ替えはインデックスで行われます

    並べ替えは少し注意が必要です。 ENUM値は、値ではなく、インデックス番号に従って格納されます。以下のコードと図3に続く出力を確認してください。

    SELECT DISTINCT 
     country AS CountryName
    ,country + 0 AS CountryId
    FROM people
    ORDER BY country;

    値に基づいて並べ替える場合は、次のように列をCHARにキャストします。

    SELECT DISTINCT 
     country AS CountryName
    ,country + 0 AS CountryId
    FROM people
    ORDER BY CAST(country AS char);

    これはどうですか?

    SELECT DISTINCT 
     country AS CountryName
    ,country + 0 AS CountryId
    FROM people
    ORDER BY CountryName;

    見た目から、値は並べ替えに使用されます。しかし、そうではありません。出力は図3と同じになります。CASTを使用したORDERBYは、値で並べ替えるのに最適な方法です。

    7。 MySQLENUMストレージ 最大2バイトのみ

    公式ドキュメントによると、MySQLENUMのデフォルトストレージにはインデックスが含まれています。結果のテーブルは、値を格納する場合に比べてコンパクトになります。 1〜255の可能な値を持つ列挙の場合は1バイト。 256〜65,535の可能な値に対して2バイト。

    しかし、私があなたに伝えたい秘密があります。

    もちろん、ストレージに関しては、値はインデックスよりも多くを占めます。適切なテーブルデザインではストレージのフットプリントが小さくなるため、別の国のテーブルを使用して別のテーブルを作成しましょう。

    CREATE TABLE country
    (
       id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
       countryname varchar(30) NOT NULL,
       modifieddate datetime DEFAULT NOW()
    );
    
    CREATE TABLE people_no_enums
    (
      id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
      lastname varchar(30) NOT NULL,
      firstname varchar(30) NOT NULL,
      middlename varchar(30) NOT NULL,
      gender char(1) not NULL,
      country tinyint DEFAULT 1,
      modifieddate datetime NOT NULL DEFAULT NOW() 
    );

    それでは、同じデータを挿入しましょう。

    INSERT INTO country (id, countryname, modifieddate)
      VALUES (1, 'United States', NOW()), (2, 'Canada', NOW()), (3, 'Brazil', NOW()), 
             (4, 'United Kingdom', NOW()), (5, 'Poland', NOW()), (6, 'Ukraine', NOW()), 
             (7, 'Lithuania', NOW()), (8, 'Japan', NOW()), (9, 'Philippines', NOW()), 
             (10, 'Thailand', NOW()), (11, 'Australia', NOW()), 
             (12, 'New Zealand', NOW());
    
    INSERT INTO people_no_enums
    SELECT
     p.id
    ,p.lastname
    ,p.firstname
    ,p.middlename
    ,CASE WHEN p.gender = 1 THEN 'M' ELSE 'F' END AS gender
    ,c.id
    ,p.modifieddate
    FROM people p
    LEFT JOIN country c ON p.country = c.countryname;

    これを行うには、INFORMATION_SCHEMA.TABLESテーブルを使用します。以下のコードを参照してください:

    SELECT
    table_name,
    ROUND(((data_length + index_length)), 2) AS "Size in Bytes"
    FROM information_schema.TABLES
    WHERE table_schema = "testenumsdb"
    AND TABLE_NAME LIKE 'people%'
    ORDER BY (data_length + index_length) DESC;

    ENUM列のない正規化されたテーブルは、ENUM列のあるテーブルと比較して、同じサイズのバイトが必要です。どちらも、InnoDBストレージエンジンを使用した同じ名前の50,000レコードを持っています。しかしもちろん、新しい テーブルもスペースを占有します。 ENUMを使用する他の長所と短所を比較検討する必要があります。

    8。 MySQLENUMは文字列リテラル専用です

    MySQLENUMは文字列リテラルのみを受け入れます。したがって、以下のコードは機能しません:

    CREATE TABLE Product
    (
       id int NOT NULL PRIMARY KEY,
       productName varchar(30),
       color enum('red','orange',CONCAT('red','orange'))
    );

    Enumdatatype内のCONCAT関数は許可されていません その他の有効なSQL式。

    9。 MySQLENUMは再利用できません

    この時点から、MySQLENUMのダークサイドが表示されます。

    まず、それを再利用することはできません。別のテーブルで必要な場合は、同じ色、サイズ、優先度の列挙を複製する必要があります。以下の図6のような設計は、ENUMでは不可能です。

    上記の2つのテーブルでENUMを使用するには、2つのテーブルの優先順位リストを複製する必要があります。

    10。値を追加するには、テーブルを変更する必要があります

    性別 以前のリストでは、2つのアイテムのみを使用しようとしました:男性 および女性 。あなたの会社がLGBTQを採用することを決定した場合はどうなりますか? ALTER TABLEを実行し、列挙の最後にレズビアンを追加する必要があります。 、ゲイバイセクシュアルトランスジェンダー 、およびクィア 。コードは次のとおりです:

    ALTER TABLE people
       MODIFY COLUMN gender     
              enum('Male','Female','Lesbian','Gay','Bisexual','Transgender','Queer')     
              NOT NULL DEFAULT 'Male';

    50,000レコードのラップトップでこれを実行すると、1秒もかかりませんでした。より大きく、より複雑なテーブルは、もう少し時間がかかります。性別リストがテーブルの場合、必要なのは5つの新しい値を挿入することだけです。

    値の名前を変更するには、ALTERTABLEも必要です。別のテーブルには、簡単なUPDATEステートメントのみが必要です。

    11。考えられる値を簡単にリストアップすることはできません

    テーブルからドロップダウンリストまたはグループ化されたラジオボタンを入力しますか?カントリーテーブルがあれば簡単です。 SELECT idを実行します 、国名 FROM 、ドロップダウンリストに入力する準備が整いました。

    しかし、MySQL ENUMでこれをどのように行うのでしょうか?

    まず、次のように、INFORMATION_SCHEMA.COLUMNSテーブルから列情報を取得します。

    /* Get the possible values for country ENUM. */
    SELECT  
     TABLE_NAME
    ,COLUMN_NAME
    ,COLUMN_TYPE
    FROM information_schema.columns
    WHERE TABLE_SCHEMA='testenumsdb'
      AND TABLE_NAME = 'people'
      AND COLUMN_NAME = 'country';

    次に、ドロップダウンリストに入力する前に、その文字列を解析してフォーマットする必要があります。かなり古風ですよね?

    しかし、最後に1つあります。

    12。 MySQLENUMは非標準です

    ENUMは、ANSISQL標準のMySQL拡張機能です。他のRDBMS製品はこれをサポートしていません。したがって、プロジェクトを開始する前に、適切なMySQLチュートリアルを参照してください。たとえば、ENUMでいっぱいのMySQLデータベースをSQL Serverに移植する必要がある場合は、回避策を実行する必要があります。回避策は、SQLServerでターゲットテーブルを設計する方法によって異なります。

    ボトムライン

    MySQLENUMを使用することの長所と短所を比較検討する必要があります。適切な正規化が適用された別のテーブルを持つことは、不確実な将来において最も柔軟です。

    追加のポイントを歓迎します。だから、下のコメントセクションに行き、それについて教えてください。これをお気に入りのソーシャルメディアプラットフォームで共有することもできます。


    1. TypeError:'int'オブジェクトはインデックス作成をサポートしていません

    2. MariaDBでのUUID_SHORT()のしくみ

    3. SQLServer2017のデータ型のリスト

    4. sqliteデータベースをSDカードに直接保存する方法