1. 程式人生 > >MySQL中 enum 插入的時候註意事項

MySQL中 enum 插入的時候註意事項

mysql enum坑

今天在執行開發發過來的工單的時候,source批量導入執行時候發現報了很多警告 提示 truncate for column xxxxx 。導入完成後,使用select查詢後,發現大量數據未成功插入。


後來發現是enum字段沒有加引號搞的鬼。



結論:

enum的字段,在插入的時候,必須帶上引號。否則會出現不可預期的問題。

驗證過程如下:


[none] > use test;


[test] > create table t1(

a int primary key auto_increment,

b enum(‘4‘,‘3‘,‘2‘,‘1‘) default ‘3‘);


[test] > INSERT INTO t1 (b) VALUES (4);

Query OK, 1 row affected

Time: 0.012s


[test] > INSERT INTO t1 (b) VALUES (‘4‘);

Query OK, 1 row affected

Time: 0.012s


[test] > SELECT * from t1;

+-----+-----+

| a | b |

|-----+-----|

| 1 | 1 | ---> 這裏我們執行的是 INSERT INTO t1 (b) VALUES (4); 結果卻插入的是數值1,和我們實際上的目標結果完全不一致。

| 2 | 4 | ---> 這裏我們執行的是 INSERT INTO t1 (b) VALUES (‘4‘); 這裏插入帶引號的4,和我們的預期結果一致。

+-----+-----+


原因:

enum類型的字段插入數值的時候, 帶引號的時候,插入的才是真正的數值。 如果不帶引號插入的話,實際上是插入的key(如上面的例子中 INSERT INTO t1 (b) VALUES (4),插入的是b列第四個default值,也就是取enum(‘4‘,‘3‘,‘2‘,‘1‘)第四個默認值,即最終插入的是數值1)。



試驗,寬松sql_mode下的插入情況:

[test] > set session sql_mode=‘‘;


[test] > INSERT INTO t1 (b) VALUES (5); ---> 插入一個超出enum下標範圍的值

Query OK, 1 row affected

Time: 0.012s


[test] > INSERT INTO t1 (b) VALUES (‘5‘); ---> 插入一個不在enum允許的值

Query OK, 1 row affected

Time: 0.011s



[test] > SELECT * from t1;

+-----+-----+

| a | b |

|-----+-----|

| 1 | 1 |

| 2 | 4 |

| 3 | |

| 4 | |

+-----+-----+


[test] > SELECT * from t1 where b = ‘‘;

+-----+-----+

| a | b |

|-----+-----|

| 3 | |

| 4 | |

+-----+-----+


[test] > SELECT * from t1 where b is null;

+-----+-----+

| a | b |

|-----+-----|

+-----+-----+

可以看到在sql_mode為空的時候,雖然插入的時候沒有報錯,但是實際上查詢是沒有結果的,(查出來後插入的2行的b是‘‘空值,不是NULL)。



繼續試驗,嚴格的sql_mode下異常插入的情況:

[test] > set session sql_mode=‘STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION‘;


[test] > INSERT INTO t1 (b) VALUES (‘5‘);

(1265, u"Data truncated for column ‘b‘ at row 1")


[test] > INSERT INTO t1 (b) VALUES (5);

(1265, u"Data truncated for column ‘b‘ at row 1")


可以看到嚴格的sql_mode下,我們的異常插入就直接報錯了。




ENUM枚舉

一般不建議使用,後期不便於擴展。任何不在枚舉的範圍的值插入都會報錯,一般用tinyint替代ENUM比較合適。

ENUM的字段值不區分大小寫。如insert into tb1 values("M"); 和insert into tb1 values("m");效果一樣的。




補充:

enum的存儲原理:

(http://justwinit.cn/post/7354/?utm_source=tuicool&utm_medium=referral)

在建立enum類型的字段時,我們會給他規定一個範圍比如 enum(‘a‘,‘b‘,‘c‘),這時mysql內部會建立一張hash結構的map表,類似:0000 -> a,0001 -> b,0002 -> c。

當我插入一條數據,此字段的值位a或b或c時,他存儲在裏面的不是這個字符,而是對應他的索引,也就是那個0000或0001或0002。

同樣,enum在mysql手冊上的說明:

ENUM(‘value1‘,‘value2‘,...)

1或2個字節,取決於枚舉值的個數(最多65,535個值)

除非enum的個數超過了一定數量,否則他所占的存儲空間也總是1字節。


本文出自 “菜雞” 博客,請務必保留此出處http://lee90.blog.51cto.com/10414478/1933603

MySQL中 enum 插入的時候註意事項