sql >> Databáze >  >> RDS >> Mysql

Datový typ ENUM (Enumeration) v MySQL:12 nejdůležitějších faktů a užitečných tipů

Data MySQL ENUM jsou řetězcový datový typ s hodnotou vybranou ze seznamu povolených hodnot. Tyto povolené hodnoty nastavíte během vytváření tabulky, jak je uvedeno níže:

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

Snadné, že?

Pro začátečníky je ověření dat okamžité bez další tabulky a cizího klíče. V přísném režimu serveru to znamená, že nemůžete vynutit nesprávné zadání. To je skvělé!

Nebo ano?

Jako každá jiná věc na světě to není vždy šťastně až do smrti.

Po přečtení následujících 12 klíčových faktů o MySQL ENUM se můžete rozhodnout, zda je to dobré pro vaši další databázi nebo tabulku v MySQL.

Pro tento článek je verze MySQL 8.0.23 a úložiště je InnoDB.

1. MySQL ENUM je typ páru klíč/hodnota řetězce

MySQL ENUM je pár klíč/hodnota. Hodnoty jsou řetězce a klíče jsou čísla indexů.

Ale kde je index?

MySQL automaticky přiřadí čísla tak, jak se objeví ve vašem seznamu. Takže ať už se jedná o užší seznam barev, typy zákazníků, pozdravy nebo způsoby platby, čísla budou přiřazena. To je pevný seznam, který se nikdy nebude rozšiřovat. Myslete na 20 nebo méně položek a hodnot, které nikdy nebudou mít další atributy. Jinak potřebujete stůl.

Ale jak jsou tyto indexy číslovány?

2. Index MySQL ENUM začíná 1, ale může být NULL nebo nula

Začnu příkladem.

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

Zde jsou 2 hodnoty MySQL ENUM: genderzemě . Dovolte mi začít s pohlavím sloupec, který obsahuje 2 hodnoty:Muž a Žena . Index pro Muž je 1 a Žena je 2. To znamená, že indexy klíčů začínají 1.

Z tohoto jednoduchého příkladu můžete určit index pro země sloupec. Má 12 hodnot. Začíná to Spojenými státy s indexem 1 a končí Novým Zélandem s indexem 12.

Poznámka :tento index neodkazuje na indexy tabulek, které používáme pro rychlé vyhledávání.

Kromě těchto čísel od 1 do 65 535 mohou být sloupce ENUM také NULL nebo nula. V našem příkladu země sloupec přijímá NULL. Takže kromě indexů 1 až 12 je NULL dalším možným indexem s hodnotou NULL.

Můžete mít také index 0. K tomu dochází v následujících situacích:

  • Režim serveru pro vaše MySQL není přísný.
  • Vložíte hodnotu, která není na seznamu povolených hodnot.
  • Pak bude vložení úspěšné, ale hodnota je prázdný řetězec s indexem nula.

Abyste předešli chybám, vždy používejte přísný režim serveru.

3. MySQL ENUM Omezuje možné hodnoty ve sloupci

V přísném režimu země sloupec v našem příkladu dříve přijme pouze 12 možných hodnot. Pokud se o to pokusíte, zobrazí se chyba „Data zkrácena pro sloupec ‚země‘“:

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

Níže uvedená chybová zpráva se objevila, protože Jižní Korea není na uvedeném seznamu.

Chybová zpráva je stejná jako v MySQL Workbench.

Pokud zde použitý server MySQL rozlišuje velká a malá písmena, nebude přijato ani toto:

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

Proč? Pohlaví jsme definovali jako Muž , nikoli MALE . A země jsou Spojené státy americké , nikoli USA.

Nakonec výčtové hodnoty v datovém typu MySQL ENUM fungují jako omezení cizího klíče, ale bez další tabulky.

Kromě toho existuje další výhoda, kterou data MySQL ENUM poskytují.

4. Přátelský výstup bez použití JOIN

Nejsou potřeba JOINy, ale výstup je přátelský. Vezměme si níže uvedený příklad ENUM v MySQL, abychom to vysvětlili:

SELECT * FROM people 
WHERE country = 4;

Tento dotaz vyhledá lidi ze Spojeného království. Ve výchozím nastavení vidíte řetězce, které jste definovali, ve sloupci ENUM. Ale interně jsou očíslované indexy uloženy. Zde je výsledek:

Poznámka :Data, která vidíte, byla vygenerována pomocí Nástroj pro generování dat dbForge Studio for MySQL. Pomocí tohoto nástroje jsem vygeneroval 50 000 jmen.

Mezitím lze stejného výstupu dosáhnout při použití samostatné tabulky a spojení.

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;

Měli byste tedy používat MySQL ENUM, abyste se JOINům úplně vyhnuli? Určitě ne! To je dobré pro malý, ale pevný seznam. Více dat s neurčitým počtem řádků a více atributů vyžaduje tabulku. A abyste vytvořili přátelštější výstup jako na obrázku 2, budete potřebovat také JOIN. Samostatná tabulka je flexibilnější a nevyžaduje od vývojáře nic, když jsou data aktivní. To není případ Enumdatatype.

5. Filtrování výčtu MySQL podle indexu nebo hodnoty řetězce

V bodě #4 jste viděli příklad s klauzulí WHERE pro filtrování pomocí sloupce ENUM. K určení země používal index. Takže to bude fungovat také:

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

Můžete také použít hodnotu řetězce, jako je ta níže:

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

6. Řazení je podle Index

Řazení může být trochu složité. Hodnoty ENUM se ukládají podle indexových čísel, nikoli podle hodnoty. Podívejte se na kód níže a výstup, který následuje na obrázku 3.

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

Pokud chcete, aby bylo řazení založeno na hodnotě, přetypujte sloupec do CHAR, jako je ten níže.

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

Co říkáte na tohle?

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

Podle vzhledu bude hodnota použita pro řazení. Ale není tomu tak. Výstup bude stejný jako na obrázku 3. ORDER BY s CAST je nejlepší způsob řazení podle hodnoty.

7. Úložiště MySQL ENUM je pouze do 2 bajtů

Podle oficiální dokumentace výchozí úložiště MySQL ENUM zahrnuje index. Výsledná tabulka je ve srovnání s ukládáním hodnot kompaktnější. Jeden (1) bajt pro výčty s 1 až 255 možnými hodnotami. Dva (2) bajty pro 256 až 65 535 možných hodnot.

Ale je tu tajemství, které vám chci říct.

Samozřejmě, pokud jde o úložiště, hodnoty zabírají více než index. Vzhledem k tomu, že správný design stolu vytváří menší úložný prostor, pojďme vytvořit další stůl se samostatným stolem pro zemi.

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

Nyní vložíme stejná 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;

K tomu používáme tabulku INFORMATION_SCHEMA.TABLES. Viz kód níže:

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;

Normalizovaná tabulka bez sloupců ENUM ve srovnání s tabulkou s nimi vyžaduje stejnou velikost v bajtech. Oba mají 50 000 záznamů se stejnými názvy pomocí úložiště InnoDB. Ale samozřejmě nová země stůl také zabere místo. Musíte zvážit další výhody a nevýhody používání ENUM.

8. MySQL ENUM je určeno pouze pro řetězcové literály

MySQL ENUM přijímá pouze řetězcové literály. Níže uvedený kód tedy nebude fungovat:

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

Funkce CONCAT uvnitř Enumdatatype není povolena stejně jako další platné SQL výrazy.

9. MySQL ENUM nelze znovu použít

Od této chvíle uvidíte temnou stránku MySQL ENUM.

Za prvé, nemůžete jej znovu použít. Pokud je potřebujete v jiné tabulce, budete muset duplikovat stejnou barvu, velikost a prioritní výčty. Návrh jako na obrázku 6 níže je s ENUM nemožný.

Chcete-li použít ENUM ve 2 tabulkách výše, musíte duplikovat seznam priorit ve 2 tabulkách.

10. Přidání dalších hodnot vyžaduje úpravu tabulky

V pohlaví dříve jsme se pokusili použít pouze 2 položky:Muž a Žena . Co když se vaše společnost rozhodne přijmout LGBTQ? Musíte spustit ALTER TABLE a přidat na konec výčtu Lesbian , Gay , Bisexuál , Transgender a Queer . Zde je kód:

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

Spuštění na mém notebooku s 50 000 záznamy trvalo méně než sekundu. Větší a složitější tabulky zaberou trochu více času. Pokud je seznam pohlaví tabulka, vše, co potřebujete, je vložit 5 nových hodnot.

Přejmenování hodnoty bude také vyžadovat ALTER TABLE. Samostatná tabulka vyžaduje pouze jednoduchý příkaz UPDATE.

11. Nelze snadno vyjmenovat možné hodnoty

Vyplňujete rozevírací seznamy nebo seskupené přepínače z tabulky? Je to snadné, když máte venkovský stůl. Proveďte SELECT id , název země ZE země a jste připraveni vyplnit rozevírací seznam.

Ale jak to uděláte s MySQL ENUM?

Nejprve získejte informace o sloupcích z tabulky INFORMATION_SCHEMA.COLUMNS takto:

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

Poté musíte tento řetězec analyzovat a naformátovat, než naplníte rozevírací seznam. Docela archaické, že?

Ale je tu ještě jedna věc.

12. MySQL ENUM je nestandardní

ENUM je rozšíření MySQL ke standardu ANSI SQL. Jiné produkty RDBMS toto nepodporují. Před zahájením projektů si proto prostudujte příslušný výukový program MySQL. Pokud potřebujete například přenést svou databázi MySQL plnou ENUM na SQL Server, musíte to obejít. Zástupná řešení se budou lišit v závislosti na tom, jak navrhnete cílovou tabulku na serveru SQL.

Sečteno podtrženo

Musíte zvážit klady a zápory používání MySQL ENUM. Mít samostatnou tabulku s aplikovanou správnou normalizací je v nejisté budoucnosti nejflexibilnější.

Další body vítáme. Takže přejděte do sekce Komentáře níže a řekněte nám o tom. Můžete to také sdílet na svých oblíbených platformách sociálních médií.


  1. Jak zachovat zpětné lomítko při escapování uvozovek v MySQL – QUOTE()

  2. Postgresql Drop View

  3. Jak určit hodnotu pole, kterou nelze převést na (desítkové, plovoucí, int) v SQL Server

  4. R12.2 Cyklus oprav online Shrnutí