MySQL ENUM-data er en strengdatatype med en værdi valgt fra listen over tilladte værdier. Du indstiller disse tilladte værdier under oprettelsen af tabellen som vist nedenfor:
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'
);
Nemt, ikke?
For det første er datavalidering øjeblikkelig uden en anden tabel og en fremmednøgle. Under streng servertilstand betyder dette, at du ikke kan tvinge en forkert indtastning. Det er fantastisk!
Eller er det?
Som enhver anden ting i verden er det ikke altid et lykkeligt liv.
Efter at have læst følgende 12 nøglefakta om MySQL ENUM, kan du beslutte, om det er godt for din næste database eller tabel i MySQL.
For denne artikel er MySQL-versionen 8.0.23, og lagermotoren er InnoDB.
1. MySQL ENUM er en nøgle/strengværdipartype
MySQL ENUM er et nøgle/værdi-par. Værdier er strenge, og nøgler er indekstal.
Men hvor er indekset?
MySQL tildeler automatisk numre, som de vises på din liste. Så uanset om det handler om en shortliste over farver, kundetyper, hilsener eller betalingsmetoder, vil numre blive tildelt. Det er en fast liste, som aldrig udvides. Tænk på 20 eller færre varer og værdier, som aldrig vil have flere egenskaber. Ellers har du brug for et bord.
Men hvordan er disse indekser nummereret?
2. MySQL ENUM Index starter med 1, men kan være NULL eller nul
Jeg starter med et eksempel.
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()
);
Der er 2 MySQL ENUM-værdier her: køn og land . Lad mig starte med kønnet kolonne, der indeholder 2 værdier:Mand og Kvinde . Indekset for Mand er 1 og Kvinde er 2. Det betyder, at nøgleindeks starter med 1.
Fra dette enkle eksempel kan du identificere indekset for landet kolonne. Den har 12 værdier. Det starter med USA med et indeks på 1 og slutter med New Zealand med et indeks på 12.
Bemærk :dette indeks refererer ikke til de tabelindekser, som vi bruger til hurtige søgninger.
Udover disse tal fra 1 til 65.535 kan ENUM-kolonner også være NULL eller nul. I vores eksempel landet kolonne accepterer NULL. Så bortset fra indeks 1 til 12 er NULL et andet muligt indeks med en NULL-værdi.
Du kan også have et 0-indeks. Dette sker i følgende situationer:
- Servertilstanden for din MySQL er ikke streng.
- Du indsætter en værdi, der ikke er på listen over tilladte værdier.
- Så vil indsættelsen lykkes, men værdien er en tom streng med et indeks på nul.
For at undgå fejl skal du altid bruge en streng servertilstand.
3. MySQL ENUM begrænser de mulige værdier i en kolonne
Under streng tilstand, landet kolonne i vores eksempel tidligere vil kun acceptere 12 mulige værdier. Så hvis du prøver at gøre dette, vil fejlen "Data trunkeret for kolonne 'land'" blive kastet:
INSERT INTO people (lastname, firstname, middlename, gender, country)
VALUES ('Choi', 'Seungcheol', '','Male','South Korea');
Fejlmeddelelsen nedenfor opstod, fordi Sydkorea ikke er på den opregnede liste.
Fejlmeddelelsen er den samme som i MySQL Workbench.
Hvis MySQL-serveren, der bruges her, skelner mellem store og små bogstaver, vil dette heller ikke blive accepteret:
INSERT INTO people (lastname, firstname, middlename, gender, country)
VALUES ('Hemsworth', 'Chris', '', 'MALE', 'united states');
Hvorfor? Vi definerede kønnet som mand , ikke MALE . Og landet er USA , ikke USA.
I sidste ende fungerer opregnede værdier i MySQL ENUM-datatypen som fremmednøglebegrænsninger, men uden en anden tabel.
Bortset fra dette er der en anden fordel, MySQL ENUM-data giver.
4. Venligt output uden brug af JOIN
Intet behov for JOINs, men outputtet er venligt. Lad os tage nedenstående ENUM i MySQL eksempel for at forklare det:
SELECT * FROM people
WHERE country = 4;
Denne forespørgsel vil hente folk fra Storbritannien. Som standard ser du de strenge, du definerede i ENUM-kolonnen. Men internt er de nummererede indekser gemt. Her er resultatet:
Bemærk :De data, du ser, blev genereret ved hjælp af dbForge Studio til MySQL's datagenereringsværktøj. Jeg genererede 50.000 navne ved hjælp af værktøjet.
I mellemtiden kan det samme output opnås, når du bruger en separat tabel og en join.
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;
Så, bør du bruge MySQL ENUM for at undgå JOINs helt? Absolut ikke! Dette er godt for en lille, men fast liste. Flere data med et ubestemt antal rækker og flere attributter kræver en tabel. Og for at lave et venligere output som i figur 2, skal du også bruge en JOIN. At have en separat tabel er mere fleksibel og kræver intet af udvikleren, når data er live. Dette er ikke tilfældet med Enumdatatype.
5. Filtrer MySQL-opregning efter indeks eller strengværdi
I punkt #4 så du et eksempel med en WHERE-sætning, der skal filtreres med en ENUM-kolonne. Den brugte indekset til at angive landet. Så dette vil også virke:
SELECT * from people
WHERE country IN (1,3,5)
AND gender = 1;
Du kan også bruge strengværdien, som den nedenfor:
SELECT * FROM people
WHERE country='Philippines'
AND gender = 'Female';
6. Sortering sker efter indeks
Sortering kan være lidt vanskelig. ENUM-værdier gemmes i henhold til deres indeksnumre, ikke værdien. Tjek koden nedenfor og outputtet, der følger i figur 3.
SELECT DISTINCT
country AS CountryName
,country + 0 AS CountryId
FROM people
ORDER BY country;
Hvis du ønsker, at sorteringen skal være baseret på værdi, cast kolonnen til en CHAR, som den nedenfor.
SELECT DISTINCT
country AS CountryName
,country + 0 AS CountryId
FROM people
ORDER BY CAST(country AS char);
Hvad med det her?
SELECT DISTINCT
country AS CountryName
,country + 0 AS CountryId
FROM people
ORDER BY CountryName;
Ud fra udseendet vil værdien blive brugt til sortering. Men det er ikke tilfældet. Outputtet vil være det samme som i figur 3. ORDER BY med en CAST er den bedste måde at sortere efter værdi på.
7. MySQL ENUM-lagring er kun op til 2 bytes
Ifølge den officielle dokumentation involverer MySQL ENUM-standardlageret indekset. Den resulterende tabel er mere kompakt sammenlignet med lagring af værdierne. En (1) byte til opregninger med 1 til 255 mulige værdier. To (2) bytes for 256 til 65.535 mulige værdier.
Men der er en hemmelighed, jeg gerne vil fortælle dig.
Når det drejer sig om opbevaring, vil værdierne naturligvis fylde mere end indekset. Da korrekt borddesign giver et mindre lagerfodaftryk, lad os skabe endnu et bord med et separat landebord.
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()
);
Lad os nu indsætte de samme data.
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;
For at gøre det bruger vi tabellen INFORMATION_SCHEMA.TABLES. Se koden nedenfor:
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;
En normaliseret tabel uden ENUM-kolonner sammenlignet med en tabel med den kræver samme størrelse i bytes. Begge har 50.000 poster med de samme navne ved hjælp af InnoDB-lagringsmotoren. Men selvfølgelig det nye land bordet vil også optage plads. Du skal afveje de andre fordele og ulemper ved at bruge ENUM.
8. MySQL ENUM er kun for strenge bogstaver
MySQL ENUM accepterer kun strenge bogstaver. Så koden nedenfor virker ikke:
CREATE TABLE Product
(
id int NOT NULL PRIMARY KEY,
productName varchar(30),
color enum('red','orange',CONCAT('red','orange'))
);
CONCAT-funktionen inde i Enumdatatype er ikke tilladt samt andre gyldige SQL-udtryk.
9. MySQL ENUM kan ikke genbruges
Fra dette tidspunkt vil du se den mørke side af MySQL ENUM.
For det første kan du ikke genbruge det. Du bliver nødt til at duplikere den samme farve, størrelse og prioritetsopregning, hvis du har brug for dem i en anden tabel. Et design som det i figur 6 nedenfor er umuligt med ENUM'er.
For at bruge ENUM i de 2 tabeller ovenfor, skal du duplikere prioritetslisten på de 2 tabeller.
10. Tilføjelse af flere værdier kræver ændring af tabellen
I køn liste tidligere forsøgte vi kun at bruge 2 elementer:Mand og Kvinde . Hvad hvis din virksomhed beslutter sig for at omfavne LGBTQ? Du skal køre en ALTER TABLE og tilføje Lesbisk til slutningen af opregningen , Hoss , Biseksuel , Transkønnet og Queer . Her er koden:
ALTER TABLE people
MODIFY COLUMN gender
enum('Male','Female','Lesbian','Gay','Bisexual','Transgender','Queer')
NOT NULL DEFAULT 'Male';
At køre dette på min bærbare computer med 50.000 poster tog kun mindre end et sekund. Større og mere komplekse borde vil forbruge lidt mere tid. Hvis kønslisten er en tabel, skal du blot indsætte de 5 nye værdier.
Omdøbning af en værdi kræver også ALTER TABLE. En separat tabel kræver kun en nem UPDATE-sætning.
11. Du kan ikke nemt opregne mulige værdier
Udfylder du dropdown-lister eller grupperede radioknapper fra en tabel? Det er nemt, når du har et landbord. Lav et SELECT id , landenavn FRA land , og du er klar til at udfylde rullelisten.
Men hvordan vil du gøre dette med MySQL ENUM?
Få først kolonneoplysningerne fra tabellen INFORMATION_SCHEMA.COLUMNS, sådan her:
/* 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';
Derefter skal du parse den streng og formatere den, før du udfylder en rulleliste. Ganske arkaisk, ikke?
Men der er en sidste ting.
12. MySQL ENUM er ikke-standard
ENUM er en MySQL-udvidelse til ANSI SQL-standarden. Andre RDBMS-produkter understøtter ikke dette. Så se den relevante MySQL-tutorial, før du starter dine projekter. Hvis du for eksempel skal portere din MySQL-database fuld af ENUM'er til SQL Server, skal du lave en løsning. Løsninger vil variere afhængigt af, hvordan du designer måltabellen i SQL Server.
Bundlinje
Du skal afveje fordele og ulemper ved at bruge MySQL ENUM. At have en separat tabel med korrekt normalisering er det mest fleksible i den usikre fremtid.
Vi glæder os over yderligere point. Så gå videre til kommentarsektionen nedenfor og fortæl os om det. Du kan også dele dette på dine foretrukne sociale medieplatforme.