Mysql
 sql >> Datenbank >  >> RDS >> Mysql

ENUM (Enumeration) Datentyp in MySQL:Top 12 Fakten und nützliche Tipps

MySQL-ENUM-Daten sind ein String-Datentyp mit einem Wert, der aus der Liste der zulässigen Werte ausgewählt wird. Diese zulässigen Werte legen Sie während der Tabellenerstellung wie folgt fest:

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'
);

Einfach, nicht wahr?

Für den Anfang erfolgt die Datenvalidierung sofort ohne eine weitere Tabelle und einen Fremdschlüssel. Im strengen Servermodus bedeutet dies, dass Sie keine falsche Eingabe erzwingen können. Das ist großartig!

Oder doch?

Wie alles andere auf der Welt ist es nicht immer ein Happy End.

Nachdem Sie die folgenden 12 Schlüsselfakten über MySQL ENUM gelesen haben, können Sie entscheiden, ob es für Ihre nächste Datenbank oder Tabelle in MySQL gut ist.

Für diesen Artikel ist die MySQL-Version 8.0.23 und die Speicher-Engine InnoDB.

1. MySQL ENUM ist ein Schlüssel/String-Wert-Paartyp

MySQL ENUM ist ein Schlüssel/Wert-Paar. Werte sind Zeichenfolgen und Schlüssel sind Indexnummern.

Aber wo ist der Index?

MySQL weist Nummern automatisch zu, wenn sie in Ihrer Liste erscheinen. Egal, ob es sich um eine Auswahlliste von Farben, Kundentypen, Anreden oder Zahlungsmethoden handelt, es werden Nummern vergeben. Das ist eine feste Liste, die niemals erweitert wird. Denken Sie an 20 oder weniger Elemente und Werte, die niemals weitere Attribute haben werden. Andernfalls benötigen Sie eine Tabelle.

Aber wie werden diese Indizes nummeriert?

2. Der MySQL-ENUM-Index beginnt mit 1, kann aber NULL oder Null sein

Ich beginne mit einem Beispiel.

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() 
);

Hier gibt es zwei MySQL-ENUM-Werte: gender und Land . Lassen Sie mich mit dem Geschlecht beginnen Spalte, die 2 Werte enthält:Männlich und Weiblich . Der Index für Männlich ist 1 und weiblich ist 2. Das bedeutet, dass Schlüsselindizes mit 1 beginnen.

Anhand dieses einfachen Beispiels können Sie den Index für das Land identifizieren Säule. Es hat 12 Werte. Es beginnt mit den Vereinigten Staaten mit einem Index von 1 und endet mit Neuseeland mit einem Index von 12.

Hinweis :Dieser Index bezieht sich nicht auf die Tabellenindizes, die wir für schnelle Suchen verwenden.

Neben diesen Zahlen von 1 bis 65.535 können ENUM-Spalten auch NULL oder Null sein. In unserem Beispiel das Land Spalte akzeptiert NULL. Neben den Indizes 1 bis 12 ist also NULL ein weiterer möglicher Index mit einem NULL-Wert.

Sie können auch einen 0-Index haben. Dies geschieht in den folgenden Situationen:

  • Der Servermodus für Ihr MySQL ist nicht strikt.
  • Sie fügen einen Wert ein, der nicht auf der Liste der zulässigen Werte steht.
  • Dann wird die Einfügung erfolgreich sein, aber der Wert ist ein leerer String mit einem Index von Null.

Verwenden Sie immer einen strengen Servermodus, um Fehler zu vermeiden.

3. MySQL ENUM begrenzt die möglichen Werte in einer Spalte

Im strikten Modus das Land Spalte in unserem vorherigen Beispiel akzeptiert nur 12 mögliche Werte. Wenn Sie dies also versuchen, wird der Fehler „Daten für Spalte „Land“ abgeschnitten“ ausgegeben:

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

Die folgende Fehlermeldung ist aufgetreten, weil Südkorea nicht auf der Aufzählungsliste steht.

Die Fehlermeldung ist dieselbe wie in MySQL Workbench.

Wenn beim hier verwendeten MySQL-Server die Groß-/Kleinschreibung beachtet wird, wird dies ebenfalls nicht akzeptiert:

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

Wieso den? Wir haben das Geschlecht als Männlich definiert , nicht MÄNNLICH . Und das Land ist Vereinigte Staaten , nicht USA.

Am Ende verhalten sich Aufzählungswerte im MySQL-ENUM-Datentyp wie Fremdschlüsseleinschränkungen, aber ohne eine weitere Tabelle.

Abgesehen davon gibt es noch einen weiteren Vorteil, den MySQL ENUM-Daten bieten.

4. Freundliche Ausgabe ohne die Verwendung von JOIN

Keine Notwendigkeit für JOINs, aber die Ausgabe ist freundlich. Nehmen wir das folgende ENUM in MySQL-Beispiel, um es zu erklären:

SELECT * FROM people 
WHERE country = 4;

Diese Abfrage ruft Personen aus dem Vereinigten Königreich ab. Standardmäßig sehen Sie die von Ihnen definierten Zeichenfolgen in der Spalte ENUM. Aber intern werden die nummerierten Indizes gespeichert. Hier ist das Ergebnis:

Hinweis :Die angezeigten Daten wurden mit generiert dbForge Studio für das Datengenerierungstool von MySQL. Ich habe mit dem Tool 50.000 Namen generiert.

In der Zwischenzeit kann die gleiche Ausgabe erzielt werden, wenn eine separate Tabelle und ein Join verwendet werden.

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;

Sollten Sie also MySQL ENUM verwenden, um JOINs ganz zu vermeiden? Definitiv nicht! Dies ist gut für eine kleine, aber feste Liste. Mehr Daten mit einer unbestimmten Anzahl von Zeilen und mehr Attributen erfordern eine Tabelle. Und für eine freundlichere Ausgabe wie in Abbildung 2 benötigen Sie auch einen JOIN. Eine separate Tabelle ist flexibler und erfordert nichts vom Entwickler, wenn die Daten live sind. Dies ist bei Enumdatatype nicht der Fall.

5. MySQL-Aufzählung nach Index oder Zeichenfolgenwert filtern

In Punkt 4 haben Sie ein Beispiel mit einer WHERE-Klausel zum Filtern mit einer ENUM-Spalte gesehen. Es verwendete den Index, um das Land anzugeben. Das wird also auch funktionieren:

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

Sie können auch den Zeichenfolgenwert wie den folgenden verwenden:

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

6. Die Sortierung erfolgt nach Index

Das Sortieren kann etwas schwierig sein. ENUM-Werte werden nach ihrer Indexnummer gespeichert, nicht nach dem Wert. Sehen Sie sich den folgenden Code und die Ausgabe an, die in Abbildung 3 folgt.

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

Wenn Sie möchten, dass die Sortierung auf dem Wert basiert, wandeln Sie die Spalte in ein CHAR um, wie das folgende.

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

Wie wäre es damit?

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

So wie es aussieht, wird der Wert zum Sortieren verwendet. Aber das ist nicht der Fall. Die Ausgabe ist dieselbe wie in Abbildung 3. ORDER BY mit einem CAST ist die beste Art, nach Wert zu sortieren.

7. MySQL-ENUM-Speicher ist nur bis zu 2 Bytes

Laut der offiziellen Dokumentation umfasst der Standardspeicher von MySQL ENUM den Index. Die resultierende Tabelle ist im Vergleich zum Speichern der Werte kompakter. Ein (1) Byte für Aufzählungen mit 1 bis 255 möglichen Werten. Zwei (2) Bytes für 256 bis 65.535 mögliche Werte.

Aber es gibt ein Geheimnis, das ich dir verraten möchte.

Wenn es um die Speicherung geht, belegen die Werte natürlich mehr als der Index. Da ein korrektes Tabellendesign einen geringeren Speicherbedarf erzeugt, erstellen wir eine weitere Tabelle mit einer separaten Ländertabelle.

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() 
);

Lassen Sie uns nun dieselben Daten einfügen.

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;

Dazu verwenden wir die Tabelle INFORMATION_SCHEMA.TABLES. Siehe folgenden Code:

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;

Eine normalisierte Tabelle ohne ENUM-Spalten benötigt im Vergleich zu einer Tabelle damit die gleiche Größe in Bytes. Beide haben 50.000 gleichnamige Datensätze, die die InnoDB-Speicher-Engine verwenden. Aber natürlich das neue Land Tisch nimmt auch Platz ein. Sie müssen die anderen Vor- und Nachteile der Verwendung von ENUM abwägen.

8. MySQL ENUM ist nur für String-Literale

MySQL ENUM akzeptiert nur Zeichenfolgenliterale. Der folgende Code funktioniert also nicht:

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

Die CONCAT-Funktion innerhalb des Enumdatatype ist nicht erlaubt sowie andere gültige SQL-Ausdrücke.

9. MySQL ENUM kann nicht wiederverwendet werden

Ab diesem Punkt sehen Sie die dunkle Seite von MySQL ENUM.

Erstens können Sie es nicht wiederverwenden. Sie müssen dieselben Farb-, Größen- und Prioritätsaufzählungen duplizieren, wenn Sie sie in einer anderen Tabelle benötigen. Ein Design wie in Abbildung 6 unten ist mit ENUMs nicht möglich.

Um ENUM in den 2 Tabellen oben zu verwenden, müssen Sie die Prioritätenliste in den 2 Tabellen duplizieren.

10. Das Hinzufügen weiterer Werte erfordert eine Änderung der Tabelle

Im Geschlecht In der vorherigen Liste haben wir versucht, nur 2 Elemente zu verwenden:Männlich und Weiblich . Was ist, wenn sich Ihr Unternehmen für LGBTQ entscheidet? Sie müssen ALTER TABLE ausführen und am Ende der Aufzählung Lesbian hinzufügen , Schwul , Bisexuell , Transgender , und Queer . Hier ist der Code:

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

Das Ausführen auf meinem Laptop mit 50.000 Datensätzen dauerte nur weniger als eine Sekunde. Größere und komplexere Tabellen benötigen etwas mehr Zeit. Wenn die Geschlechterliste eine Tabelle ist, brauchen Sie nur die 5 neuen Werte einzufügen.

Das Umbenennen eines Werts erfordert auch ALTER TABLE. Eine separate Tabelle erfordert nur eine einfache UPDATE-Anweisung.

11. Sie können mögliche Werte nicht einfach auflisten

Füllen Sie Dropdown-Listen oder gruppierte Optionsfelder aus einer Tabelle? Es ist einfach, wenn Sie eine Ländertabelle haben. Führen Sie eine SELECT id durch , Ländername AUS Land , und schon können Sie die Dropdown-Liste füllen.

Aber wie machen Sie das mit MySQL ENUM?

Rufen Sie zunächst die Spalteninformationen aus der Tabelle INFORMATION_SCHEMA.COLUMNS wie folgt ab:

/* 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';

Anschließend müssen Sie diese Zeichenfolge analysieren und formatieren, bevor Sie eine Dropdown-Liste füllen. Ziemlich archaisch, nicht wahr?

Aber da ist noch eine letzte Sache.

12. MySQL ENUM ist kein Standard

ENUM ist eine MySQL-Erweiterung des ANSI-SQL-Standards. Andere RDBMS-Produkte unterstützen dies nicht. Lesen Sie daher das entsprechende MySQL-Tutorial, bevor Sie mit Ihren Projekten beginnen. Wenn Sie beispielsweise Ihre MySQL-Datenbank voller ENUMs auf SQL Server portieren müssen, müssen Sie einen Workaround durchführen. Problemumgehungen variieren je nachdem, wie Sie die Zieltabelle in SQL Server entwerfen.

Unterm Strich

Sie müssen die Vor- und Nachteile der Verwendung von MySQL ENUM abwägen. In der ungewissen Zukunft ist es am flexibelsten, eine separate Tabelle mit richtiger Normalisierung zu haben.

Wir freuen uns über zusätzliche Punkte. Gehen Sie also weiter zum Kommentarbereich unten und erzählen Sie uns davon. Sie können dies auch auf Ihren bevorzugten Social-Media-Plattformen teilen.