Mysql
 sql >> Database >  >> RDS >> Mysql

Tipo di dati ENUM (enumerazione) in MySQL:i 12 principali fatti e suggerimenti utili

I dati MySQL ENUM sono un tipo di dati stringa con un valore scelto dall'elenco dei valori consentiti. Puoi impostare questi valori consentiti durante la creazione della tabella come mostrato di seguito:

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

Facile, vero?

Per cominciare, la convalida dei dati è istantanea senza un'altra tabella e una chiave esterna. In modalità server rigoroso, ciò significa che non puoi forzare una voce sbagliata. Questo è fantastico!

O lo è?

Come qualsiasi altra cosa al mondo, non è sempre un lieto fine.

Dopo aver letto i seguenti 12 fatti chiave su MySQL ENUM, puoi decidere se è adatto al tuo prossimo database o tabella in MySQL.

Per questo articolo, la versione di MySQL è 8.0.23 e il motore di archiviazione è InnoDB.

1. MySQL ENUM è un tipo di coppia chiave/stringa valore

MySQL ENUM è una coppia chiave/valore. I valori sono stringhe e le chiavi sono numeri di indice.

Ma dov'è l'indice?

MySQL assegna automaticamente i numeri man mano che appaiono nell'elenco. Quindi, che si tratti di una rosa di colori, tipi di clienti, saluti o metodi di pagamento, i numeri verranno assegnati. Questa è una lista fissa che non si allargherà mai. Pensa a 20 o meno elementi e valori che non avranno mai ulteriori attributi. Altrimenti, hai bisogno di un tavolo.

Ma come sono numerati questi indici?

2. L'indice MySQL ENUM inizia con 1 ma può essere NULL o zero

Comincio con un esempio.

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

Ci sono 2 valori MySQL ENUM qui: generepaese . Vorrei iniziare con il genere colonna che contiene 2 valori:Maschio e Femmina . L'indice per Maschio è 1 e Femmina è 2. Ciò significa che gli indici delle chiavi iniziano con 1.

Da questo semplice esempio, puoi identificare l'indice per il paese colonna. Ha 12 valori. Inizia con gli Stati Uniti con un indice di 1 e termina con la Nuova Zelanda con un indice di 12.

Nota :questo indice non fa riferimento agli indici delle tabelle che utilizziamo per le ricerche veloci.

Oltre a questi numeri da 1 a 65.535, le colonne ENUM possono anche essere NULL o zero. Nel nostro esempio, il paese la colonna accetta NULL. Quindi, a parte gli indici da 1 a 12, NULL è un altro possibile indice con un valore NULL.

Puoi anche avere un indice 0. Ciò accade nelle seguenti situazioni:

  • La modalità server per il tuo MySQL non è rigida.
  • Inserisci un valore che non è nell'elenco dei valori consentiti.
  • Quindi, l'inserimento avrà esito positivo, ma il valore è una stringa vuota con indice zero.

Per evitare errori, utilizza sempre una modalità server rigorosa.

3. MySQL ENUM limita i valori possibili in una colonna

In modalità rigorosa, il paese la colonna nel nostro esempio precedente accetterà solo 12 valori possibili. Quindi, se provi a farlo, verrà generato l'errore "Dati troncati per la colonna 'paese'":

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

Il seguente messaggio di errore si è verificato perché la Corea del Sud non è nell'elenco enumerato.

Il messaggio di errore è lo stesso di MySQL Workbench.

Se il server MySQL utilizzato qui fa distinzione tra maiuscole e minuscole, anche questo non sarà accettato:

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

Come mai? Abbiamo definito il genere come Maschio , non MASCHIO . E il paese sono gli Stati Uniti , non Stati Uniti.

Alla fine, i valori enumerati nel tipo di dati MySQL ENUM agiscono come vincoli di chiave esterna ma senza un'altra tabella.

Oltre a questo, c'è un altro vantaggio fornito dai dati MySQL ENUM.

4. Output amichevole senza l'uso di JOIN

Non c'è bisogno di JOIN, ma l'output è amichevole. Prendiamo l'esempio ENUM di seguito in MySQL per spiegarlo:

SELECT * FROM people 
WHERE country = 4;

Questa query recupererà persone dal Regno Unito. Per impostazione predefinita, vedi le stringhe che hai definito nella colonna ENUM. Ma internamente, gli indici numerati vengono archiviati. Ecco il risultato:

Nota :I dati che vedi sono stati generati utilizzando dbForge Studio per lo strumento di generazione dati di MySQL. Ho generato 50.000 nomi utilizzando lo strumento.

Nel frattempo, è possibile ottenere lo stesso risultato utilizzando una tabella separata e un 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;

Quindi, dovresti usare MySQL ENUM per evitare del tutto i JOIN? Sicuramente no! Questo è buono per un elenco piccolo ma fisso. Più dati con un numero indefinito di righe e più attributi richiedono una tabella. E per creare un output più semplice come nella Figura 2, avrai anche bisogno di un JOIN. Avere una tabella separata è più flessibile e non richiede nulla allo sviluppatore quando i dati sono attivi. Questo non è il caso di Enumdatatype.

5. Filtra l'enumerazione MySQL per indice o valore stringa

Nel punto #4, hai visto un esempio con una clausola WHERE da filtrare con una colonna ENUM. Ha usato l'indice per specificare il paese. Quindi funzionerà anche questo:

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

Puoi anche utilizzare il valore della stringa, come quello di seguito:

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

6. L'ordinamento è per Indice

L'ordinamento può essere un po' complicato. I valori ENUM vengono memorizzati in base ai loro numeri di indice, non al valore. Controlla il codice seguente e l'output che segue nella Figura 3.

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

Se desideri che l'ordinamento sia basato sul valore, esegui il cast della colonna su un CHAR, come quello di seguito.

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

Che ne dici di questo?

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

A quanto pare, il valore verrà utilizzato per l'ordinamento. Ma non è così. L'output sarà lo stesso della Figura 3. ORDER BY con un CAST è il modo migliore per ordinare per valore.

7. Archiviazione MySQL ENUM è solo fino a 2 byte

Secondo la documentazione ufficiale, lo storage predefinito di MySQL ENUM coinvolge l'indice. La tabella risultante è più compatta rispetto alla memorizzazione dei valori. Un (1) byte per enumerazioni con da 1 a 255 valori possibili. Due (2) byte da 256 a 65.535 possibili valori.

Ma c'è un segreto che voglio svelarti.

Naturalmente, quando si tratta di archiviazione, i valori occuperanno più dell'indice. Poiché il design corretto del tavolo produce un ingombro di archiviazione inferiore, creiamo un altro tavolo con una tabella Paese separata.

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

Ora inseriamo gli stessi dati.

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;

Per farlo, utilizziamo la tabella INFORMATION_SCHEMA.TABLES. Vedi il codice qui sotto:

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;

Una tabella normalizzata senza colonne ENUM rispetto a una tabella con essa richiede la stessa dimensione in byte. Entrambi hanno 50.000 record con lo stesso nome utilizzando il motore di archiviazione InnoDB. Ma ovviamente il nuovo paese anche il tavolo occuperà spazio. Devi valutare gli altri vantaggi e svantaggi dell'utilizzo di ENUM.

8. MySQL ENUM è solo per stringhe letterali

MySQL ENUM accetta solo stringhe letterali. Quindi, il codice seguente non funzionerà:

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

La funzione CONCAT all'interno di Enumdatatype non è consentita così come altre espressioni SQL valide.

9. MySQL ENUM non può essere riutilizzato

Da questo punto, vedrai il lato oscuro di MySQL ENUM.

Innanzitutto, non puoi riutilizzarlo. Dovrai duplicare le stesse enumerazioni di colore, dimensione e priorità se ne hai bisogno in un'altra tabella. Un design come quello nella Figura 6 di seguito è impossibile con gli ENUM.

Per utilizzare ENUM nelle 2 tabelle precedenti, è necessario duplicare l'elenco delle priorità sulle 2 tabelle.

10. L'aggiunta di più valori richiede la modifica della tabella

Nel genere elenco in precedenza, abbiamo provato a utilizzare solo 2 elementi:Maschio e Femmina . E se la tua azienda decidesse di abbracciare il LGBTQ? Devi eseguire un ALTER TABLE e aggiungere alla fine dell'enumerazione Lesbiche , Gay , Bisessuale , Transgender e Queer . Ecco il codice:

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

L'esecuzione sul mio laptop con 50.000 record ha richiesto solo meno di un secondo. Tabelle più grandi e complesse consumeranno un po' più di tempo. Se l'elenco dei sessi è una tabella, è sufficiente inserire i 5 nuovi valori.

Anche la ridenominazione di un valore richiederà ALTER TABLE. Una tabella separata richiede solo una semplice istruzione UPDATE.

11. Non puoi elencare facilmente i possibili valori

Popoli elenchi a discesa o pulsanti di opzione raggruppati da una tabella? È facile quando hai un tavolo country. Fai un SELECT id , nome del paese DA paese e sei pronto per popolare l'elenco a discesa.

Ma come lo farai con MySQL ENUM?

Innanzitutto, ottieni le informazioni sulla colonna dalla tabella INFORMATION_SCHEMA.COLUMNS, in questo modo:

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

Quindi, devi analizzare quella stringa e formattarla prima di popolare un elenco a discesa. Abbastanza arcaico, vero?

Ma c'è un'ultima cosa.

12. MySQL ENUM non è standard

ENUM è un'estensione MySQL dello standard ANSI SQL. Altri prodotti RDBMS non supportano questo. Quindi, fai riferimento al tutorial MySQL appropriato prima di iniziare i tuoi progetti. Ad esempio, se è necessario trasferire il database MySQL pieno di ENUM su SQL Server, è necessario eseguire una soluzione alternativa. Le soluzioni alternative variano a seconda di come si progetta la tabella di destinazione in SQL Server.

Linea inferiore

Devi valutare i pro ei contro dell'utilizzo di MySQL ENUM. Avere una tabella separata con una corretta normalizzazione applicata è la più flessibile in un futuro incerto.

Diamo il benvenuto a punti aggiuntivi. Quindi, vai alla sezione Commenti qui sotto e raccontacelo. Puoi anche condividerlo sulle tue piattaforme di social media preferite.