MySql支持的数据类型

mysql支持的数据类型

# mysql数据库支持存放哪些数据

# 整型 | 浮点型 | 字符型 | 时间类型 | 枚举类型 | 集合类型

整型

类型 大小 范围(有符号) 范围(无符号) 用途
TINYINT 1 字节 (-128,127) (0,255) 小整数值
SMALLINT 2 字节 (-32 768,32 767) (0,65 535) 大整数值
MEDIUMINT 3 字节 (-8 388 608,8 388 607) (0,16 777 215) 大整数值
INT或INTEGER 4 字节 (-2 147 483 648,2 147 483 647) (0,4 294 967 295) 大整数值
BIGINT 8 字节 (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) (0,18 446 744 073 709 551 615) 极大整数值
'''约束
unsigned:无符号
zerofill:0填充
'''
3位  1 001
# 建表
mysql>: create table tb1(x tinyint, y smallint, z int(6));

# 插入数据
mysql>: insert into tb1 values(128, 32768, 32768);  # 结果:127,32767,32768

# 结论:整型的长度由所占字节(取值范围)决定,可以自定义长度,但是不影响所占字节(取值范围)
# 	 所有整型变量的长度一般都省略不写,不同类型所占字节数不一样, 决定所占空间及存放数据的大小限制
结论>: create table tb1(x tinyint, y smallint, z int);


# 整型约束
mysql>: create table tb2(x tinyint unsigned);  # 0~255
mysql>: insert into tb2 values(256), (-1);    # 255, 0
    
# 0填充约束
mysql>: create table tb3(x tinyint unsigned zerofill);
mysql>: insert into tb3 values(10);  # 010

'''宽度
1.不能决定整型存放数据的宽度, 超过宽度可以存放, 最终由数据类型所占字节决定
2.如果没有超过宽度,且有zerofill限制, 会用0填充前置位的不足位
3.没有必要规定整型的宽度, 默认设置的宽度就为该整型能存放数据的最大宽度 *
'''

浮点型

类型 大小 范围(有符号) 范围(无符号) 用途
FLOAT 4 字节 (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) 0,(1.175 494 351 E-38,3.402 823 466 E+38) 单精度 浮点数值
DOUBLE 8 字节 (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 双精度 浮点数值
DECIMAL 对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2 依赖于M和D的值 依赖于M和D的值 小数值
# 在安全模式下测试浮点型类型

'''类型
float(M, D):4字节,3.4E–38~3.4E+38
double(M, D):8字节,1.7E–308~1.7E+308
decimal(M, D):所在字节M,D大值基础上+2,其实就是M值+2就是decimal字段所占字节数,(M, D) => M为位数,D为小数位
'''
'''宽度:
限制存储宽度
(M, D) => M为位数,D为小数位,M要大于等于D
float(255, 30):精度最低,最常用
double(255, 30):精度高,占位多
decimal(65, 30):字符串存,全精度
'''

# 建表:
mysql>: create table tb4 (age float(256, 30)); # Display width out of range for column 'age' (max = 255)
mysql>: create table tb5 (age float(255, 31)); # Too big scale 31 specified for column 'age'. Maximum is 30.
mysql>: create table tb5 (age float(65, 30)); # 在合理取值范围
    
mysql>: create table t12 (x float(255, 30));
mysql>: create table t13 (x double(255, 30));
mysql>: create table t14 (x decimal(65, 30));
# 1.111111164093017600000000000000 
mysql>: insert into t12 values(1.11111111111111111119);  
# 1.111111111111111200000000000000
mysql>: insert into t13 values(1.11111111111111111119);
# 1.111111111111111111190000000000
mysql>: insert into t14 values(1.11111111111111111119);

# 重点:长度与小数位分析
# 报错,总长度M必须大于等于小数位D
mysql>: create table t14 (x decimal(2, 3));
# 能存储 -0.9999
mysql>: create table t14 (x decimal(3, 3));

字符串:

数据库优化 - char效率要高于varchar

类型 大小 用途
CHAR 0-255字节 定长字符串
VARCHAR 0-65535 字节 变长字符串
TINYBLOB 0-255字节 不超过 255 个字符的二进制字符串
TINYTEXT 0-255字节 短文本字符串
BLOB 0-65 535字节 二进制形式的长文本数据
TEXT 0-65 535字节 长文本数据
MEDIUMBLOB 0-16 777 215字节 二进制形式的中等长度文本数据
MEDIUMTEXT 0-16 777 215字节 中等长度文本数据
LONGBLOB 0-4 294 967 295字节 二进制形式的极大文本数据
LONGTEXT 0-4 294 967 295字节 极大文本数据

​ CHAR 和 VARCHAR 类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面 也不同。在存储或检索过程中不进行大小写转换。

​ BINARY 和 VARBINARY 类似于 CHAR 和 VARCHAR,不同的是它们包含二进制字符串而不要非二进制字符 串。也就是说,它们包含字节字符串而不是字符字符串。这说明它们没有字符集,并且排序和比较基于列值 字节的数值值。

​ BLOB 是一个二进制大对象,可以容纳可变数量的数据。有 4 种 BLOB 类型:TINYBLOB、BLOB、 MEDIUMBLOB 和 LONGBLOB。它们区别在于可容纳存储范围不同。

​ 有 4 种 TEXT 类型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。对应的这 4 种 BLOB 类型,可存储的 最大长度不同,可根据实际情况选择。

'''类型
char:定长
varchar:不定长
'''
'''宽度
限制存储宽度
char(4):以4个字符存储定长存储数据
varchar(4):数据长度决定字符长度,为可变长度存储数据
'''
# eg:
create table t15 (x char(4), y varchar(4));
insert into t15 values("zero", 'owen'); # '' | "" 均可以表示字符
select x,y from t15; # 正常
insert into t15 values("yanghuhu", 'lxxVSegon'); # 非安全模式数据丢失,可以存放, 安全模式报错
select x,y from t15; # 可以正常显示丢失后(不完整)的数据
insert into t15 values('a', 'b');

# 验证数据所在字符长度
# 前提: 安全模式下以空白填充字符
set global sql_mode="strict_trans_tables,PAD_CHAR_TO_FULL_LENGTH";
# 重启连接
select char_length(x), char_length(y) from t15; # a占4 b占1

'''重点: 存储数据的方式 **  => 数据库优化
char: 一定按规定的宽度存放数据, 以规定宽度读取数据, 通常更占空间
varchar: 首先根据数据长度计算所需宽度, 并在数据开始以数据头方式将宽度信息保存起来, 是一个计算耗时过程, 取先读取宽度信息,以宽度信息为依准读取数据, 通常节省空间
'''
8: zero    egon    lxx     yanghuhu
8: 4zero4egon3lxx8yanghuhu
注: varchar的数据头占1~2字节
    规定char|varchar宽度均为4,用来存放4个字符的数据, char存取更高效,char占4字符,varchar占5字符,char更省空间

总结: 数据长度相近的数据提倡用char来存放数据, 数据需要高速存取,以空间换时间, 采用char

时间

​ 每个时间类型有一个有效值范围和一个"零"值,当指定不合法的MySQL不能表示的值时使用"零"值。

类型 大小 (字节) 范围 格式 用途
DATE 3 1000-01-01/9999-12-31 YYYY-MM-DD 日期值
TIME 3 '-838:59:59'/'838:59:59' HH:MM:SS 时间值或持续时间
YEAR 1 1901/2155 YYYY 年份值
DATETIME 8 1000-01-01 00:00:00/9999-12-31 23:59:59 YYYY-MM-DD HH:MM:SS 混合日期和时间值
TIMESTAMP 4 1970-01-01 00:00:00/2038结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 YYYYMMDD HHMMSS 混合日期和时间值,时间戳
'''类型
year:yyyy(1901/2155)
date:yyyy-MM-dd(1000-01-01/9999-12-31)
time:HH:mm:ss
datetime:yyyy-MM-dd HH:mm:ss(1000-01-01 00:00:00/9999-12-31 23:59:59)
timestamp:yyyy-MM-dd HH:mm:ss(1970-01-01 00:00:00/2038-01-19 ??)
'''
# eg: 1
create table t16(my_year year, my_date date, my_time time);
insert into t16 values(); # 三个时间类型的默认值均是null
insert into t16 values(2156, null, null); # 在时间范围外,不允许插入该数据
insert into t16 values(1, '2000-01-01 12:00:00', null); # 2001 2000-01-01 null
insert into t16 values(2019, '2019-01-08', "15-19-30"); # time报格式错误 => 按照时间规定格式存放数据

alter table t16 change my_year myYear year(2); # 时间的宽度修改后还是采用默认宽度 => 不需要关系宽度


# eg:2
create table t17(my_datetime datetime, my_timestamp timestamp);
insert into t17 values(null, null); # 可以为空, 不能为null,赋值null采用默认值current_timestamp
insert into t17 values('4000-01-01 12:00:00', '2000-01-01 12:00:00'); # 在各自范围内可以插入对应格式的时间数据

# datetime VS timestamp
datetime:时间范围,不依赖当前时区,8字节,可以为null
timestamp:时间范围,依赖当前时区,4字节,有默认值CURRENT_TIMESTAMP

二进制数据(_Blob)

​ 1._BLOB和_text存储方式不同,_TEXT以文本方式存储,英文存储区分大小写,而_Blob是以二进制方式存储,不 分大小写。

​ 2._BLOB存储的数据只能整体读出。

​ 3._TEXT可以指定字符集,_BLO不用指定字符集。

MYSQL数据类型的长度和范围

各数据类型及字节长度一览表:

数据类型 字节长度 范围或用法
Bit 1 无符号[0,255],有符号[-128,127],天缘博客备注:BIT和BOOL布尔型都占用1字节
TinyInt 1 整数[0,255]
SmallInt 2 无符号[0,65535],有符号[-32768,32767]
MediumInt 3 无符号[0,224-1],有符号[-223,2^23-1]]
Int 4 无符号[0,232-1],有符号[-231,2^31-1]
BigInt 8 无符号[0,264-1],有符号[-263 ,2^63 -1]
Float(M,D) 4 单精度浮点数。天缘博客提醒这里的D是精度,如果D<=24则为默认的FLOAT,如果D>24则会自动被转换为DOUBLE型。
Double(M,D) 8 双精度浮点。
Decimal(M,D) M+1或M+2 未打包的浮点数,用法类似于FLOAT和DOUBLE,天缘博客提醒您如果在ASP中使用到Decimal数据类型,直接从数据库读出来的Decimal可能需要先转换成Float或Double类型后再进行运算。
Date 3 以YYYY-MM-DD的格式显示,比如:2009-07-19
Date Time 8 以YYYY-MM-DD HH:MM:SS的格式显示,比如:2009-07-19 11:22:30
TimeStamp 4 以YYYY-MM-DD的格式显示,比如:2009-07-19
Time 3 以HH:MM:SS的格式显示。比如:11:22:30
Year 1 以YYYY的格式显示。比如:2009
Char(M) M 定长字符串。
VarChar(M) M 变长字符串,要求M<=255
Binary(M) M 类似Char的二进制存储,特点是插入定长不足补0
VarBinary(M) M 类似VarChar的变长二进制存储,特点是定长不补0
Tiny Text Max:255 大小写不敏感
Text Max:64K 大小写不敏感
Medium Text Max:16M 大小写不敏感
Long Text Max:4G 大小写不敏感
TinyBlob Max:255 大小写敏感
Blob Max:64K 大小写敏感
MediumBlob Max:16M 大小写敏感
LongBlob Max:4G 大小写敏感
Enum 1或2 最大可达65535个不同的枚举值
Set 可达8 最大可达64个不同的值
Geometry
Point
LineString
Polygon
MultiPoint
MultiLineString
MultiPolygon
GeometryCollection

使用建议

​ 1、在指定数据类型的时候一般是采用从小原则,比如能用TINY INT的最好就不用INT,能用FLOAT类型的就 不用DOUBLE类型,这样会对MYSQL在运行效率上提高很大,尤其是大数据量测试条件下。

​ 2、不需要把数据表设计的太过复杂,功能模块上区分或许对于后期的维护更为方便,慎重出现大杂烩数据表

​ 3、数据表和字段的起名字也是一门学问

​ 4、设计数据表结构之前请先想象一下是你的房间,或许结果会更加合理、高效

​ 5、数据库的最后设计结果一定是效率和可扩展性的折中,偏向任何一方都是欠妥的

选择数据类型的基本原则

前提:使用适合存储引擎。

选择原则:根据选定的存储引擎,确定如何选择合适的数据类型。

下面的选择方法按存储引擎分类:

  • MyISAM 数据存储引擎和数据列:MyISAM数据表,最好使用固定长度(CHAR)的数据列代替可变长度(VARCHAR)的数据列。
  • MEMORY存储引擎和数据列:MEMORY数据表目前都使用固定长度的数据行存储,因此无论使用CHAR或VARCHAR列都没有关系。两者都是作为CHAR类型处理的。
  • InnoDB 存储引擎和数据列:建议使用 VARCHAR类型。

对于InnoDB数据表,内部的行存储格式没有区分固定长度和可变长度列(所有数据行都使用指向数据列值的头指针),因此在本质上,使用固定长度的CHAR列不一定比使用可变长度VARCHAR列简单。因而,主要的性能因素是数据行使用的存储总量。由于CHAR平均占用的空间多于VARCHAR,因 此使用VARCHAR来最小化需要处理的数据行的存储总量和磁盘I/O是比较好的。

下面说一下固定长度数据列与可变长度的数据列。

char与varchar

CHAR和VARCHAR类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。

下面的表显示了将各种字符串值保存到CHAR(4)和VARCHAR(4)列后的结果,说明了CHAR和VARCHAR之间的差别:

CHAR(4) 存储需求 VARCHAR(4) 存储需求
'' ' ' 4个字节 '' 1个字节
'ab' 'ab ' 4个字节 'ab ' 3个字节
'abcd' 'abcd' 4个字节 'abcd' 5个字节
'abcdefgh' 'abcd' 4个字节 'abcd' 5个字节

请注意上表中最后一行的值只适用不使用严格模式时;如果MySQL运行在严格模式,超过列长度不的值不保存,并且会出现错误。

从CHAR(4)和VARCHAR(4)列检索的值并不总是相同,因为检索时从CHAR列删除了尾部的空格。通过下面的例子说明该差别:
mysql> CREATE TABLE vc (v VARCHAR(4), c CHAR(4));
Query OK, 0 rows affected (0.02 sec)

mysql> INSERT INTO vc VALUES ('ab ', 'ab ');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT CONCAT(v, '+'), CONCAT(c, '+') FROM vc;
+----------------+----------------+
| CONCAT(v, '+') | CONCAT(c, '+') |
+----------------+----------------+
| ab + | ab+ |
+----------------+----------------+
1 row in set (0.00 sec)

text和blob

在使用text和blob字段类型时要注意以下几点,以便更好的发挥数据库的性能。

①BLOB和TEXT值也会引起自己的一些问题,特别是执行了大量的删除或更新操作的时候。删除这种值会在数据表中留下很大的"空洞",以后填入这些"空洞"的记录可能长度不同,为了提高性能,建议定期使用 OPTIMIZE TABLE 功能对这类表进行碎片整理.

②使用合成的(synthetic)索引。合成的索引列在某些时候是有用的。一种办法是根据其它的列的内容建立一个散列值,并把这个值存储在单独的数据列中。接下来你就可以通过检索散列值找到数据行了。但是,我们要注意这种技术只能用于精确匹配的查询(散列值对于类似<或>=等范围搜索操作符 是没有用处的)。我们可以使用MD5()函数生成散列值,也可以使用SHA1()或CRC32(),或者使用自己的应用程序逻辑来计算散列值。请记住数值型散列值可以很高效率地存储。同样,如果散列算法生成的字符串带有尾部空格,就不要把它们存储在CHAR或VARCHAR列中,它们会受到尾部空格去除的影响。

合成的散列索引对于那些BLOB或TEXT数据列特别有用。用散列标识符值查找的速度比搜索BLOB列本身的速度快很多。

③在不必要的时候避免检索大型的BLOB或TEXT值。例如,SELECT *查询就不是很好的想法,除非你能够确定作为约束条件的WHERE子句只会找到所需要的数据行。否则,你可能毫无目的地在网络上传输大量的值。这也是 BLOB或TEXT标识符信息存储在合成的索引列中对我们有所帮助的例子。你可以搜索索引列,决定那些需要的数据行,然后从合格的数据行中检索BLOB或 TEXT值。

④把BLOB或TEXT列分离到单独的表中。在某些环境中,如果把这些数据列移动到第二张数据表中,可以让你把原数据表中 的数据列转换为固定长度的数据行格式,那么它就是有意义的。这会减少主表中的碎片,使你得到固定长度数据行的性能优势。它还使你在主数据表上运行 SELECT *查询的时候不会通过网络传输大量的BLOB或TEXT值。

浮点数与定点数

为了能够引起大家的重视,在介绍浮点数与定点数以前先让大家看一个例子:
mysql> CREATE TABLE test (c1 float(10,2),c2 decimal(10,2));
Query OK, 0 rows affected (0.29 sec)

mysql> insert into test values(131072.32,131072.32);
Query OK, 1 row affected (0.07 sec)

mysql> select * from test;
+-----------+-----------+
| c1 | c2 |
+-----------+-----------+
| 131072.31 | 131072.32 |
+-----------+-----------+
1 row in set (0.00 sec)

从上面的例子中我们看到c1列的值由131072.32变成了131072.31,这就是浮点数的不精确性造成的。

在mysql中float、double(或real)是浮点数,decimal(或numberic)是定点数。

浮点数相对于定点数的优点是在长度一定的情况下,浮点数能够表示更大的数据范围;它的缺点是会引起精度问题。在今后关于浮点数和定点数的应用中,大家要记住以下几点:

  1. 浮点数存在误差问题;
  2. 对货币等对精度敏感的数据,应该用定点数表示或存储;
  3. 编程中,如果用到浮点数,要特别注意误差问题,并尽量避免做浮点数比较;
  4. 要注意浮点数中一些特殊值的处理。

补充

​ 1、一个汉字占多少长度与编码有关:

UTF-8:一个汉字=3个字节

GBK:一个汉字=2个字节

​ 2、varchar(n) 表示 n 个字符,无论汉字和英文,Mysql 都能存入 n 个字符,仅是实际字节长度有所区别

​ 3、MySQL 检查长度,可用 SQL 语言来查看:

select LENGTH(字段名) from 表名

枚举与集合

枚举类型,enum

每个枚举值均有一个索引值:

在列说明中列表值所允许的成员值被从 1 开始编号。

一般来说就是单选,在定义枚举的时候列出所有的可能性;

代码如下

1. create table type_enum(  
2. gender enum('male','remale','serect'),  
3. );  
4. insert into type_enum values ('remale');  


在处理时,类似字符串型进行操作!

意义在于:

1, 限定值的可能性!

2, 速度快,比普通的字符串速度快!

原因是枚举型 是利用 整数进行管理的,能够2个字节进行管理!

每个值,都是一个整数标识,从第一个选项开始为1,逐一递增!

管理时整数的形式,速度比字符串快!

一共有2 个字节,0-65535,因此可以有 65535个选项可以使用!、

集合 set 不定想项选

类似于 enum枚举,在定义时,也需要指定其已有值!

与字符串相比,优势是:

1, 也是采用 整数进行管理的!采用位运算,从第一位开始为1,逐一x2!

2, 每个集合类型8个字节,64位,因此可以表示64个元素!

注意:站在 mysql的角度,尽量多用枚举和集合!

扩展:

集合 set 扩展

在创建表时,就指定SET类型的取值范围。

属性名 SET('值1','值2','值3'...,'值n')

其中,“属性名”参数指字段的名称;“值n”参数表示列表中的第n个值,这些值末尾的空格将会被系统直接删除。其基本形式与ENUM类型一样。SET类型的值可以取列表中的一个元素或者多个元素的组合。取多个元素时,不同元素之间用逗号隔开。SET类型的值最多只能是有64个元素构成的组合,根据成员的不同,存储上也有所不同:

1~8成员的集合,占1个字节。
9~16成员的集合,占2个字节。
17~24成员的集合,占3个字节。
25~32成员的集合,占4个字节。
33~64成员的集合,占8个字节。

同ENUM类型一样,列表中的每个值都有一个顺序排列的编号。MySQL中存入的是这个编号,而不是列表中的值。

插入记录时,SET字段中的元素顺序无关紧要。存入MySQL数据库后,数据库系统会自动按照定义时的顺序显示。如果插入的成员中有重复,则只存储一次。

枚举类型,enum扩展

ENUM类型(枚举类型),与C#的概念一样,在定义时指定取值范围。

ENUM类型的值范围需要在创建表时通过枚举方式显式指定,对1~255个成员的枚举需要1个字节存储;对于256~65535个成员,需要2个字节存储。最多可以有65535个成员,而SET类型最多只能包含64个成员。两者的取值只能在成员列表中选取。ENUM类型只能从成员中选择一个,而SET类型可以选择多个。

因此,对于多个值中选取一个的,可以选择ENUM类型。例如,“性别”字段就可以定义成ENUM类型,因为只能在“男”和“女”中选其中一个。对于可以选取多个值的字段,可以选择SET类型。例如,“爱好”字段就可以选择SET类型,因为可能有多种爱好。

属性名 ENUM('值1','值2','值3'...'值n')

◆其中,属性名参数指字段的名称;“值n”参数表示列表中的第n个值,这些值末尾的空格将会被系统直接删除。ENUM类型的值只能取列表中的一个元素。其取值列表中最多能有65535个值。列表中的每个值都有一个顺序排列的编号,MySQL中存入的是这个编号,而不是列表中的值。

◆ENUM 有 NOT NULL 属性,其默认值为取值列表的第一个元素;
◆ENUM 无 NOT NULL,则ENUM类型将允许插入NULL,并且NULL为默认值;

CREATE TABLE Test4(Sex ENUM('男','女'));
INSERT INTO Test4 VALUES('男');
INSERT INTO Test4 VALUES('爷'); --这行报错
SELECT * FROM Test4;

ENUM 是一个字符串对象,其值通常选自一个允许值列表中,该列表在表创建时的列规格说明中被明确地列举。

在下列某些情况下,值也可以是空串('') 或 NULL:
◆如果将一个无效值插入一个 ENUM (即,一个不在允许值列表中的字符串),空字符串将作为一个特殊的错误值被插入。事实上,这个字符串有别于一个'普通的'空字符串,因为这个字符串有个数字索引值为 0。稍后有更详细描述。
◆如果一个 ENUM 被声明为 NULL,NULL 也是该列的一个合法值,并且该列的缺省值也将为 NULL 。如果一个 ENUM 被声明为 NOT NULL,该列的缺省值将是该列表所允许值的第一个成员。

每个枚举值均有一个索引值:
◆在列说明中列表值所允许的成员值被从 1 开始编号。
◆空字符串错误值的索引值为 0。这就意味着,你可以使用下面所示的 SELECT 语句找出被赋于无效 ENUM值的记录行。
mysql> SELECT * FROM tbl_name WHERE enum_col=0;
◆NULL 值的索引值为 NULL。

例如,指定为 ENUM('one', 'two', 'three') 的一个列,可以有下面所显示的任一值。每个值的索引值也如下所示:

索引值
NULL NULL
'' 0
'one' 1
'two' 2
'three' 3

换个枚举最大可以有 65535 个成员值。

从 MySQL 3.23.51 开始,当表被创建时,ENUM 值尾部的空格将会自动删除。

当为一个 ENUM 列赋值时,字母的大小写是无关紧要的。然而,以后从列中检索出来的值的大小写却是匹配于创建表时所指定的允许值。

如果在一个数字语境中检索一个ENUM,列值的索引值将被返回。例如,你可以像这样使用数字值检索一个 ENUM 列:

mysql> SELECT enum_col+0 FROM tbl_name;

如果将一个数字存储到一个 ENUM 中,数字被当作为一个索引值,并且存储的值是该索引值所对应的枚举成员。(但是,这在 LOAD DATA 将不能工作,因为它视所有的输入均为字符串。) 在一个 ENUM 字符串中存储数字是不明智的,因为它可能会打乱思维。

ENUM 值依照列规格说明中的列表顺序进行排序。(换句话说,ENUM 值依照它们的索引号排序。)举例来说,对于 ENUM('a', 'b') 'a' 排在 'b' 后,但是对于 ENUM('b', 'a') , 'b' 却排在 'a' 之前。空字符串排在非空字符串前,NULL 值排在其它所有的枚举值前。为了防止意想不到的结果,建议依照字母的顺序定义 ENUM 列表。也可以通过使用 GROUP BY CONCAT(col) 来确定该以字母顺序排序而不是以索引值。

如果希望得到一个 ENUM 列的所有可能值,可以使用:

SHOW COLUMNS FROM table_name LIKE enum_colum;

SET 与 ENUM 类型的查询修改操作
SET FOREIGN_KEY_CHECKS=0;


-- Table structure for setenum


DROP TABLE IF EXISTS setenum;
CREATE TABLE setenum (
id int(11) NOT NULL AUTO_INCREMENT,
settype set('we','周','李','孙','钱','赵') DEFAULT NULL,
enumtype enum('ZZZ','南海','长江','黄河') DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;


-- Records of setenum


INSERT INTO setenum VALUES ('1', 'we,周,钱', '南海');
INSERT INTO setenum VALUES ('2', '钱,赵', '黄河');
INSERT INTO setenum VALUES ('3', 'we,赵', '南海');
INSERT INTO setenum VALUES ('4', '李,孙,钱', '长江');

set('we','周','李','孙','钱','赵')=111111=63
enum('ZZZ','南海','长江','黄河')=100=4

如下表所示:

SET类型:低位(右) → 高位(左)

we
1 1 1 1 1 1

从右到左排:11111=63

we
1 1 0 0 1 0

从右到左排:010011=19

we
0 0 0 0 1 1

从右到左排:110000=48

we
1 0 0 0 0 1

从右到左排:100001=33

we
0 0 1 1 1 0

从右到左排:011100=28

ENUM类型

ZZZ 南海 长江 黄河
1 2 3 4
ZZZ 南海 长江 黄河
1 2 3 4

黄河=4=100

ZZZ 南海 长江 黄河
1 2 3 4

长江=3=11

ZZZ 南海 长江 黄河
1 2 3 4

南海=2=10

ZZZ 南海 长江 黄河
1 2 3 4

ZZZ=1=1

mysql> select * from setenum;
+----+----------+----------+
| id | settype | enumtype |
+----+----------+----------+
| 1 | we,周,钱 | 南海 |
| 2 | 钱,赵 | 黄河 |
| 3 | we,赵 | 南海 |
| 4 | 李,孙,钱 | 长江 |
+----+----------+----------+
4 rows in set

mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum;
+----------+-----------+----------------+----------+------------+-----------------+
| settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) |
+----------+-----------+----------------+----------+------------+-----------------+
| we,周,钱 | 19 | 10011 | 南海 | 2 | 10 |
| 钱,赵 | 48 | 110000 | 黄河 | 4 | 100 |
| we,赵 | 33 | 100001 | 南海 | 2 | 10 |
| 李,孙,钱 | 28 | 11100 | 长江 | 3 | 11 |
+----------+-----------+----------------+----------+------------+-----------------+
4 rows in set

mysql> select * from setenum where settype=33;
+----+---------+----------+
| id | settype | enumtype |
+----+---------+----------+
| 3 | we,赵 | 南海 |
+----+---------+----------+
1 row in set

mysql> select * from setenum where enumtype=2;
+----+----------+----------+
| id | settype | enumtype |
+----+----------+----------+
| 1 | we,周,钱 | 南海 |
| 3 | we,赵 | 南海 |
+----+----------+----------+
2 rows in set

--不支持二进制查询
mysql> select * from setenum where settype=b'010011';
Empty set

mysql> select * from setenum where settype=b'10011';
Empty set

mysql> select * from setenum where enumtype=b'100';
Empty set

mysql> SELECT * FROM setenum WHERE settype LIKE '%赵%';
+----+---------+----------+
| id | settype | enumtype |
+----+---------+----------+
| 2 | 钱,赵 | 黄河 |
| 3 | we,赵 | 南海 |
+----+---------+----------+
2 rows in set

--与FIND_IN_SET函数同
mysql> SELECT * FROM setenum WHERE FIND_IN_SET('赵',settype)>0;
+----+---------+----------+
| id | settype | enumtype |
+----+---------+----------+
| 2 | 钱,赵 | 黄河 |
| 3 | we,赵 | 南海 |
+----+---------+----------+
2 rows in set

--当查询只是集合某个值的一部分时,与FIND_IN_SET函数不同
mysql> SELECT * FROM setenum WHERE FIND_IN_SET('e',settype)>0;
Empty set

mysql> SELECT * FROM setenum WHERE settype LIKE '%e%';
+----+----------+----------+
| id | settype | enumtype |
+----+----------+----------+
| 1 | we,周,钱 | 南海 |
| 3 | we,赵 | 南海 |
+----+----------+----------+
2 rows in set

mysql> SELECT * FROM setenum WHERE settype LIKE '赵';
Empty set

mysql> SELECT * FROM setenum WHERE settype = '赵';
Empty set

mysql> SELECT * FROM setenum WHERE settype LIKE 'we,赵';
+----+---------+----------+
| id | settype | enumtype |
+----+---------+----------+
| 3 | we,赵 | 南海 |
+----+---------+----------+
1 row in set

mysql> SELECT * FROM setenum WHERE settype = 'we,赵';
+----+---------+----------+
| id | settype | enumtype |
+----+---------+----------+
| 3 | we,赵 | 南海 |
+----+---------+----------+
1 row in set

--如果把集合的顺序改一下,照样无效
mysql> SELECT * FROM setenum WHERE settype LIKE '赵,we';
Empty set

mysql> SELECT * FROM setenum WHERE settype = '赵,we';
Empty set

mysql> SELECT * FROM setenum WHERE enumtype LIKE '%海%';

+----+----------+----------+
| id | settype | enumtype |
+----+----------+----------+
| 1 | we,周,钱 | 南海 |
| 3 | we,赵 | 南海 |
+----+----------+----------+
2 rows in set

mysql> SELECT * FROM setenum WHERE enumtype = '南海';
+----+----------+----------+
| id | settype | enumtype |
+----+----------+----------+
| 1 | we,周,钱 | 南海 |
| 3 | we,赵 | 南海 |
+----+----------+----------+
2 rows in set

mysql> SELECT * FROM setenum WHERE enumtype = '海';
Empty set

--------------------UPDATE 语法--------------------

set('we','周','李','孙','钱','赵')=111111=63

mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1;
+----------+-----------+----------------+----------+------------+-----------------+
| settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) |
+----------+-----------+----------------+----------+------------+-----------------+
| we,周,钱 | 19 | 10011 | 南海 | 2 | 10 |
+----------+-----------+----------------+----------+------------+-----------------+
1 row in set

mysql> update setenum set settype = 2 where id=1;
Query OK, 1 row affected
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1;
+---------+-----------+----------------+----------+------------+-----------------+
| settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) |
+---------+-----------+----------------+----------+------------+-----------------+
| 周 | 2 | 10 | 南海 | 2 | 10 |
+---------+-----------+----------------+----------+------------+-----------------+
1 row in set

--修改settype让其'we'、'周'、'李' 成员为真
mysql> update setenum set settype =settype|1|4|6 where id=1;
Query OK, 1 row affected
Rows matched: 1 Changed: 1 Warnings: 0

--|1|4|6 表示 二进制的OR运算 1 or 100 or 110 = 111 = 7
--实际与 1|6 结果是一样的:1 or 110 = 111 = 7

we
1 1 1 0 0 0

从右到左排:000111=7

mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1;
+----------+-----------+----------------+----------+------------+-----------------+
| settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) |
+----------+-----------+----------------+----------+------------+-----------------+
| we,周,李 | 7 | 111 | 南海 | 2 | 10 |
+----------+-----------+----------------+----------+------------+-----------------+
1 row in set

--实际与 1|6 结果是一样的:1 or 110 = 111 = 7
mysql> update setenum set settype =settype|1|6 where id=1;
Query OK, 0 rows affected
Rows matched: 1 Changed: 0 Warnings: 0

mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1;
+----------+-----------+----------------+----------+------------+-----------------+
| settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) |
+----------+-----------+----------------+----------+------------+-----------------+
| we,周,李 | 7 | 111 | 南海 | 2 | 10 |
+----------+-----------+----------------+----------+------------+-----------------+
1 row in set

--settype|1|6 的settype 可以省略,结果一样
mysql> update setenum set settype = 1|6 where id=1;
Query OK, 1 row affected
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1;
+----------+-----------+----------------+----------+------------+-----------------+
| settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) |
+----------+-----------+----------------+----------+------------+-----------------+
| we,周,李 | 7 | 111 | 南海 | 2 | 10 |
+----------+-----------+----------------+----------+------------+-----------------+
1 row in set

-- &表示与运算,1 and 110 = 0,注意0与NULL不同
mysql> update setenum set settype = 1 & 6 where id=1;
Query OK, 1 row affected
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1;
+---------+-----------+----------------+----------+------------+-----------------+
| settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) |
+---------+-----------+----------------+----------+------------+-----------------+
| | 0 | 0 | 南海 | 2 | 10 |
+---------+-----------+----------------+----------+------------+-----------------+
1 row in set

-- &表示与运算,表示反运算,6=110,6=001,1 and 001 = 1
mysql> update setenum set settype = null where id=1;
Query OK, 1 row affected
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1;
+---------+-----------+----------------+----------+------------+-----------------+
| settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) |
+---------+-----------+----------------+----------+------------+-----------------+
| NULL | NULL | NULL | 南海 | 2 | 10 |
+---------+-----------+----------------+----------+------------+-----------------+
1 row in set

mysql> update setenum set settype = 1 & ~6 where id=1;
Query OK, 1 row affected
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1;
+---------+-----------+----------------+----------+------------+-----------------+
| settype | settype+0 | bin(settype+0) | enumtype | enumtype+0 | bin(enumtype+0) |
+---------+-----------+----------------+----------+------------+-----------------+
| we | 1 | 1 | 南海 | 2 | 10 |
+---------+-----------+----------------+----------+------------+-----------------+
1 row in set

-- 5 and ~1 = 101 and ~1 = 101 and 111110 = 100 = 4
mysql> update setenum set settype = null where id=1;
Query OK, 1 row affected
Rows matched: 1 Changed: 1 Warnings: 0

mysql> update setenum set settype = 5 & ~1 where id=1;
Query OK, 1 row affected
Rows matched: 1 Changed: 1 Warnings: 0

we
0 0 1 0 0 0

从右到左排:000100=4

mysql> select settype,settype+0,bin(settype+0),enumtype,enumtype+0,bin(enumtype+0) from setenum where id=1;
+---------+-----------+----------------+----------+------------+-----------------+

settype settype+0 bin(settype+0) enumtype enumtype+0 bin(enumtype+0)

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

4 100 南海 2 10

+---------+-----------+----------------+----------+------------+-----------------+
1 row in set

枚举和集合的简单运用
# 枚举与集合:为某一个字段提供选项的 - 枚举只能单选(1个),集合可以多选(0-n个)

# 建表
# enum、set默认值为NULL
mysql>: create table tc1 (name varchar(20), sex enum('男', '女', '哇塞'), hobbies set('男', '女', '哇塞'));
mysql>: insert into tc1 values('ruakei', '哇塞哇塞', '未知');  
    
# enum、set手动设置默认值 '男' 与 '哇塞'
mysql>: create table tc2 (name varchar(20), sex enum('男', '女', '哇塞') default '男', hobbies set('男', '女', '哇塞') default '哇塞');
mysql>: insert into tc2 values('ruakei', '哇塞哇塞', '未知');  
mysql>: insert into tc2(name) values('ruakei');
    
# 对sex、hobbies两个字段赋值错误,系统默认用空字符串填充(非安全模式),安全模式抛异常
# 如果对出sex、hobbies两个字段外的其他字段进行赋值,这两个字段会才有默认值

# 注:对set类型的字段进行赋值,用一个字符串,字符串内部用,将多个选项隔开,且不能添加空格等其他额外字符
mysql>: insert into tc2 values('ruakei_1', '女', '男,女,哇塞');  
原文地址:https://www.cnblogs.com/TMesh/p/11731226.html