每一个常量、变量和参数都有数据类型,它用来指定一定的存储格式、约束和有效范围。MySQL 提供了多种数据类型,主要包括数值型、字符串类型、日期和时间类型。
不同的 MySQL 版本支持的数据类型可能会稍有不同,用户可以通过查询相应版本的帮助文件来获得具体信息。该文章将以 MySQL5.7 版本为例,详细介绍 MySQL 中的各种数据类型。
数值类型
MySQL 支持所有标准 SQL 中的数值类型,其中包括严格数值类型(INTEGER 、SMALLINT 、DECIMAL 和 NUMERIC),以及近似数值数据类型(FLOAT 、REAL 和 DOUBLE),并在此基础上做了扩展。扩展后增加了 TINYINT 、MEDIUMINT 和 BIGINT 这三种长度不同的整型,并增加了 BIT 类型,用来存放位数据。
注:无符号,表示设置的的数据为0或者正数;有符号则可以是负数。
在整数类型中,按照取值范围和存储方式不同,分为 tinyint 、smallint 、mediumint 、int 和 bigint 这 5 个类型。如果超出类型范围的操作,会发生“Out of range”错误提示。
指定显示宽度
对于整型数据,MySQL 还支持在类型后面的小括号内指定显示宽度,例如 int(5)
表示当数值宽度小于 5 位的时候在数字前面填满宽度,如果不显示指定宽度则默认为 int(11)
。一般配合 zerofill
使用,顾名思义,zerofill
就是用“0”填充的意思,也就是在数字位不够的空间用“0”填满。
举例说明填充前后的区别:
- 创建表 T1,有 ID1 和 ID2 两个字段,指定其数值宽度分别为 INT 和 INT(5)
mysql> create table t1 (id1 int, id2 int(5)); Query OK, 0 rows affected (0.03 sec) mysql> desc t1; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | id1 | int(11) | YES | | NULL | | | id2 | int(5) | YES | | NULL | | +-------+---------+------+-----+---------+-------+ 2 rows in set (0.00 sec)
- 在 ID1 和 ID2 中都插入数值 1,可以发现格式没有异常
mysql> insert into t1 values(1, 1); Query OK, 1 row affected (0.01 sec) mysql> select * from t1; +------+------+ | id1 | id2 | +------+------+ | 1 | 1 | +------+------+ 1 row in set (0.00 sec)
- 分别修改 ID1 和 ID2 的字段类型,加入 zerofill 参数
mysql> alter table t1 modify id1 int zerofill; Query OK, 1 row affected (0.06 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> alter table t1 modify id2 int(5) zerofill; Query OK, 1 row affected (0.07 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> select * from t1; +------------+-------+ | id1 | id2 | +------------+-------+ | 0000000001 | 00001 | +------------+-------+ 1 row in set (0.00 sec)
从上述查询结果可发现,在数值前面用字符“0”填充了剩余的宽度。
AUTO_INCREMENT
在需要产生唯一标识符或顺序值时,可利用该属性,这个属性只用于整数类型。AUTO_INCREMENT
值一般从 1 开始,每行增加 1。在插入 NULL 到一个 AUTO_INCREMENT
列时,MySQL 插入一个比该列中当前最大值大 1 的值。
一个表中最多只能有一个 AUTO_INCREMENT
列。
mysql> create table ai(id int auto_increment not null primary key); Query OK, 0 rows affected (0.02 sec)
浮点数和定点数
对于小数的表示,MySQL 分为两种方式:浮点数和定点数。浮点数包括 float 和 double,而定点数则只有 decimal 一种表示。定点数在 MySQL 内部以字符串形式存放,比浮点数更精确,适合用来表示货币等精度高的数据。
浮点数和定点数都可以用类型名称后加 (M, D)
的方式来进行表示,(M, D)
表示该值一共显示 M 位数字,其中 D 位于小数点后面。M 和 D 又称为精度和标度。
举例说明 float 、double 和 decimal 三者之间的不同:
- 创建测试表 T2,分别将 ID1 、ID2 、ID3 字段设置为 float(5,2) 、double(5,2) 、decimal(5,2)
mysql> create table t2 ( id1 float(5,2) default null, id2 double(5,2) default null, id3 decimal(5,2) default null ); Query OK, 0 rows affected (0.02 sec)
- 往 ID1 、ID2 、ID3 字段中插入数据 1.23
mysql> insert into t2 values(1.23, 1.23, 1.23); Query OK, 1 row affected (0.00 sec) mysql> select * from t2; +------+------+------+ | id1 | id2 | id3 | +------+------+------+ | 1.23 | 1.23 | 1.23 | +------+------+------+ 1 row in set (0.00 sec)
- 清空表,然后向 ID1 、ID2 、ID3 字段中都插入数据 1.456
mysql> truncate table t2; Query OK, 0 rows affected (0.01 sec) mysql> insert into t2 values(1.456, 1.456, 1.456); Query OK, 1 row affected, 1 warning (0.00 sec) mysql> select * from t2; +------+------+------+ | id1 | id2 | id3 | +------+------+------+ | 1.46 | 1.46 | 1.46 | +------+------+------+ 1 row in set (0.00 sec)
从上述结果可知,此时虽然数据写入进去了,但是由于字段精度的限制,只保留了两位小数,且发生了四舍五入。
- 将 ID1 、ID2 、ID3 字段的精度和标度全部去掉,清空表,再次插入数据 1.456
mysql> alter table t2 modify id1 float; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> alter table t2 modify id2 double; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> alter table t2 modify id3 decimal; Query OK, 1 row affected, 1 warning (0.04 sec) Records: 1 Duplicates: 0 Warnings: 1 mysql> desc t2; +-------+---------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------------+------+-----+---------+-------+ | id1 | float | YES | | NULL | | | id2 | double | YES | | NULL | | | id3 | decimal(10,0) | YES | | NULL | | +-------+---------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) mysql> truncate table t2; Query OK, 0 rows affected (0.01 sec) mysql> insert into t2 values(1.456, 1.456, 1.456); Query OK, 1 row affected, 1 warning (0.00 sec) mysql> select * from t2; +-------+-------+------+ | id1 | id2 | id3 | +-------+-------+------+ | 1.456 | 1.456 | 1 | +-------+-------+------+ 1 row in set (0.00 sec)
注:对于浮点数,如果不写精度和标度,则会按照实际精度值显示数据;如果有精度和标度,则会自动将四舍五入后的结果插入,系统不会报错;定点数如果不写精度和标度,则按照默认值 decimal(10,0)
来进行操作(上述操作中,ID3 字段结果为 1 ),并且如果数据超过了精度和标度,系统则会报错。
位类型
对于 BIT(位)类型,用于存放位字段值,BIT(M) 可以用来存放多位二进制数,M 范围从 1~64,如果不写则默认为 1 位。对于位字段,直接使用 SELECT 命令将不会看到结果,可以用 bin()
显示为二进制格式,或者 hex()
显示为十六进制格式函数进行读取。
- 创建表 T3,ID 字段为 BIT 类型
mysql> create table t3 (id bit(1)); Query OK, 0 rows affected (0.02 sec) mysql> insert into t3 values(1); Query OK, 1 row affected (0.00 sec)
- 直接使用 SELECT 查询的结果为 NULL
mysql> select * from t3; +------+ | id | +------+ | | +------+ 1 row in set (0.00 sec)
- 改用 bin() 、hex() 函数,结果可以正常显示为二进制数字和十六进制数字
mysql> select bin(id), hex(id) from t3; +---------+---------+ | bin(id) | hex(id) | +---------+---------+ | 1 | 1 | +---------+---------+ 1 row in set (0.00 sec)
数据插入 BIT 类型时,首先转换为二进制,如果位数允许,将成功插入;如果位数小于实际定义的位数,则插入失败。
- 往表 T3 的 ID 列插入数字 2,由于数字 2 的二进制是“10”,而 ID 字段的定义为 BIT(1),将无法进行插入
mysql> insert into t3 values(2); ERROR 1406 (22001): Data too long for column 'id' at row 1
- 将 ID 列定义修改为 BIT(2) 后,重新插入,即可成功
mysql> alter table t3 modify id bit(2); Query OK, 1 row affected (0.05 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into t3 values(2); Query OK, 1 row affected (0.01 sec) mysql> select bin(id), hex(id) from t3; +---------+---------+ | bin(id) | hex(id) | +---------+---------+ | 1 | 1 | | 10 | 2 | +---------+---------+ 2 rows in set (0.00 sec)
日期和时间类型
MySQL 中有多种数据类型可以用于日期和时间的表示,这些数据类型的主要区别如下:
- 如果要用来表示年月日,通常用 DATE 来表示
- 如果要用来表示年月日时分秒,通常用 DATETIME 来表示
- 如果只用来表示时分秒,通常用 TIME 来表示
- 如果要经常插入或者更新日期为当前系统时间,则通常使用 TIMESTAMP 来表示
- 如果只是表示年份,可以用 YEAR 来表示,它比 DATE 占用更少的空间
举例说明 DATE 、TIME 和 DATETIME 这三种最常用的日期类型:
- 创建表 T4,字段分别为 date 、time 、datetime 三种日期类型
mysql> create table t4(d date, t time, dt datetime); Query OK, 0 rows affected (0.02 sec) mysql> desc t4; +-------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+-------+ | d | date | YES | | NULL | | | t | time | YES | | NULL | | | dt | datetime | YES | | NULL | | +-------+----------+------+-----+---------+-------+ 3 rows in set (0.00 sec)
- 用 now() 函数插入当前日期
mysql> insert into t4 values(now(), now(), now()); Query OK, 1 row affected, 1 warning (0.00 sec) mysql> select * from t4; +------------+----------+---------------------+ | d | t | dt | +------------+----------+---------------------+ | 2021-11-19 | 21:10:11 | 2021-11-19 21:10:11 | +------------+----------+---------------------+ 1 row in set (0.00 sec)
从上述结果可知,DATETIME 是 DATE 和 TIME 的组合,可以根据不同的需要,来选择不同的日期或时间类型以满足不同的需求。
字符串类型
MySQL 中提供了多种对字符数据的存储类型,包括了 CHAR 、VARCHAR 、BINARY 、TEXT 等多种字符串类型。
CHAR 和 VARCHAR 类型
CHAR 和 VARCHAR 很类似,都用来保存 MySQL 中较短的字符串。二者的主要区别在于存储方式的不同:CHAR 列的长度固定为创建表时声明的长度,长度可以为从 0 ~ 255 的任何值;而 VARCHAR 列中的值为可变长字符串,长度可以指定为 0 ~ 65536 之间的值。在检索的时候,CHAR 列删除了尾部的空格,而 VARCHAR 则保留这些空格。
- 创建表 T5,并定义两个字段 “v VARCHAR(5)” 和 “c CHAR(5)”
mysql> create table t5 (v varchar(5), c char(5)); Query OK, 0 rows affected (0.02 sec) mysql> desc t5; +-------+------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+------------+------+-----+---------+-------+ | v | varchar(5) | YES | | NULL | | | c | char(5) | YES | | NULL | | +-------+------------+------+-----+---------+-------+ 2 rows in set (0.00 sec)
- v 列和 c 列同时插入字符串 “ab ”
mysql> insert into t5 values('ab ', 'ab '); Query OK, 1 row affected (0.00 sec)
- 显示查询结果
mysql> select * from t5; +-------+------+ | v | c | +-------+------+ | ab | ab | +-------+------+ 1 row in set (0.00 sec) mysql> select length(v), length(c) from t5; +-----------+-----------+ | length(v) | length(c) | +-----------+-----------+ | 5 | 2 | +-----------+-----------+ 1 row in set (0.00 sec)
从上述结果可知,CHAR 列最后的空格在查询时都已经被删除,而 VARCHAR 依然保留空格。
BINARY 和 VARBINARY 类型
BINARY 和 VARBINARY 类型类似于 CHAR 和 VARCHAR,不同的是它们包含二进制字符串而不包含非二进制字符串。
- 创建表 T6,字段为 “c BINARY(3)”
mysql> create table t6 (c binary(3)); Query OK, 0 rows affected (0.02 sec)
- 往字段 c 中插入字符 “a”
mysql> insert into t6 set c = 'a'; Query OK, 1 row affected (0.01 sec)
- 分别用以下几种模式来查看 c 列的内容
mysql> select *, hex(c), c='a', c='a\0', c='a\0\0' from t6; +------+--------+-------+---------+-----------+ | c | hex(c) | c='a' | c='a\0' | c='a\0\0' | +------+--------+-------+---------+-----------+ | a | 610000 | 0 | 0 | 1 | +------+--------+-------+---------+-----------+ 1 row in set (0.00 sec)
从上述结果可知,当保存 BINARY 值时,在值的最后通过填充“0x00”(零字节)以达到指定的字段定义长度。对于一个 BINARY(3) 列,当插入数据“a”时,会变为“a\0\0”。
ENUM 类型
ENUM 中文名称叫枚举类型,它的值范围需要在创建表时通过指定枚举值方式显示指定。对 1 ~ 255 个成员的枚举需要 1 个字节存储;对于 255 ~ 65536 个成员,需要 2 个字节存储,最多允许有 65536 个成员。
- 创建表 T7,定义 gender 字段为枚举类型,成员为 “M” 和 “F”
mysql> create table t7 (gender enum('M', 'F')); Query OK, 0 rows affected (0.02 sec)
- 插入 4 条不同的记录
mysql> insert into t7 values('M'), ('1'), ('f'), (NULL); Query OK, 4 rows affected (0.00 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> select * from t7; +--------+ | gender | +--------+ | M | | M | | F | | NULL | +--------+ 4 rows in set (0.00 sec)
从上述结果可知,ENUM 类型时忽略大小写的,在存储 'M' 、'f' 时将它们都转成了大写,还可以看出对于插入不在 ENUM 指定范围内的值时,并没有返回警告,而是插入了 enum('M', 'F')
的第一个值 'M'。
另外,ENUM 类型只允许从值集合中选取单个值,而不能一次取多个值。
SET 类型
SET 和 ENUM 类型非常类似,也是一个字符串对象,里面可以包含 0 ~ 64 个成员。根据成员的不同,存储上也有所不同。
- 1 ~ 8 成员的集合,占 1 个字节
- 9 ~ 16 成员的集合,占 2 个字节
- 17 ~ 24 成员的集合,占 3 个字节
- 25 ~ 32 成员的集合,占 4 个字节
- 33 ~ 64 成员的集合,占 8 个字节
SET 和 ENUM 除了存储之外,最主要的区别在于 SET 类型一次可以选取多个成员,而 ENUM 只能选取一个。
- 创建表 T8
mysql> create table t8 (col set('a','b', 'c', 'd')); Query OK, 0 rows affected (0.02 sec) mysql> desc t8; +-------+----------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------------------+------+-----+---------+-------+ | col | set('a','b','c','d') | YES | | NULL | | +-------+----------------------+------+-----+---------+-------+ 1 row in set (0.00 sec)
- 插入多组不同的成员
mysql> insert into t8 values ('a,b'), ('a,d,a'), ('a,c'), ('a'); Query OK, 4 rows affected (0.00 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> select * from t8; +------+ | col | +------+ | a,b | | a,d | | a,c | | a | +------+ 4 rows in set (0.00 sec)
SET 类型可以从允许值集合中选择任意 1 个或多个元素进行组合,所以对于输入的值只要是在允许值的范围内,都可以正确地注入到 SET 类型的列中。
对于超出允许值范围的值,例如 ('a,d,f') 将不允许注入到上述例子设置的 SET 类型列中,而对于 ('a,d,a') 这样包含重复成员的集合将只取一次,写入后的结果为“a,d”。
参考资料
《深入浅出 MySQL 数据库开发 第2版 -- 唐汉明》
原创文章,转载请注明出处:http://www.opcoder.cn/article/50/