在MYSQL中每一个表的列都有其数据类型,一般的数据类型是指定数据存储格式以及存储长度。开发中最常见的数据类型是数值型、字符串型、日期时间类型等。
MYSQL数值类型包括整数类型以及浮点型类型,其中整数类型有如下类型:
类型名称 | 解释说明 | 存储空间 |
---|---|---|
TINYINT | MYSQL中最小的整数类型 | 1个字节 |
SMALLINT | MYSQL中小的整数 | 2个字节 |
MEDIUMINT | MYSQL中等大小整数 | 3个字节 |
INT | MYSQL中默认的整数类型 | 4个字节 |
BIGINT | MYSQL中最大的整数类型 | 8个字节 |
在上一篇文章中创建了tb_person的表对象,其表信息如下所示:
mysql> desc tb_person;
+---------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------+------+-----+---------+-------+
| name | varchar(50) | NO | | NULL | |
| address | varchar(50) | NO | | NULL | |
| salary | decimal(10,2) | NO | | NULL | |
| de_no | int(11) | YES | | NULL | |
+---------+---------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
de_no 字段数据类型为int(11),这表示的是该数据类型指定显示的宽度为11,这里需要注意显示宽度和实际类型存储数据最大范围是无关的,指定宽度是让MYSQL最大显示的数字长度个数,当插入的数据长度小于指定宽度时不足之处将会由空格填充。如果插入的数据大于显示的宽度但是只要没有超过该数据类型最大范围值,数值依然可以插入表中列。
显示宽度只用于显示,不会限制取值范围和占用空间,如 INT(3) 依然是占有4个字节的空间大小且最大值也不是999。
MYSQL中小数部分由浮点数与定点数组成。其中浮点型数值有以下类型:
类型名称 | 解释说明 | 存储空间 |
---|---|---|
FLOATT | 单精度小数类型 | 4个字节 |
DOUBLE | 双精度小数类型 | 8个字节 |
定点数类型只有一种:
类型名称 | 解释说明 | 存储空间 |
---|---|---|
DEC、DECIMAL(M,D) | 最大取值范围与DOUBLE相同 | M+2个字节 |
浮点数与定点数都可以使用(M,D)表示。其中(M,D) 意味着数值一共显示M个数字,其中D位位于小数点后面,一般M被称为精度,D称为标度。
下面以创建一个测试表以简单比较上述三种小数类型的区别:
mysql> create table demo1(x float(5,2),y double(5,2), z decimal(5,2))
Query OK, 0 rows affected (0.01 sec)
在x,y,z分别插入数据 5.21如下所示:
mysql> insert into demo1 values (5.21,5.21,5.21);
Query OK, 1 row affected (0.00 sec)
mysql> select * from demo1;
+------+------+------+
| x | y | z |
+------+------+------+
| 5.21 | 5.21 | 5.21 |
+------+------+------+
1 row in set (0.00 sec)
可以看到数据都已经插入成功,我们再像列中同时插入数据1.315 如下所示:
mysql> insert into demo1 values (1.315,1.315,1.315);
Query OK, 1 row affected, 1 warnings (0.01 sec)
上面插入数据时候提示了警告信息我们可以查看一下警告信息如下:
mysql> show warnings;
+-------+------+----------------------------------------+
| Level | Code | Message |
+-------+------+----------------------------------------+
| Note | 1265 | Data truncated for column 'z' at row 1 |
+-------+------+----------------------------------------+
1 rows in set (0.00 sec)
mysql> select * from demo1;
+------+------+------+
| x | y | z |
+------+------+------+
| 5.21 | 5.21 | 5.21 |
| 1.31 | 1.31 | 1.32 |
+------+------+------+
2 rows in set (0.01 sec)
可以看到的是上述X,Y存储数据时候进行了四舍五入没有出现警告信息,而z字段数值直接被截断。
我们将上述字段的精度与标度去掉然后再插入数据1.315如下所示:
mysql> alter table demo1 modify column x float;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table demo1 modify column y double;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table demo1 modify column z decimal;
Query OK, 2 rows affected, 2 warnings (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 2
mysql> desc demo1;
+-------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| x | float | YES | | NULL | |
| y | double | YES | | NULL | |
| z | decimal(10,0) | YES | | NULL | |
+-------+---------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> select * from demo1;
+-------+-------+------+
| x | y | z |
+-------+-------+------+
| 5.21 | 5.21 | 5 |
| 1.31 | 1.31 | 1 |
| 1.315 | 1.315 | 1 |
+-------+-------+------+
3 rows in set (0.00 sec)
我们发现x,y都可以进行数值的正常插入但是z字段的小数点部分已经全部被截取。
FLOAT 与 DOUBLE在不指定精度、标度时,会默认按照实际的精度进行数据插入,如果DECIMAL不指定精度则默认为DECIMAL(10,0), 如果数值类型指定了精度与标度时,则会按照四舍五入后的结果插入表中。一般在实际开发中如账户余额等对精度要求较高的情况下,一般使用的是Decimal类型且精度为10,标度为2
BIT类型可以存储二进制数据,其默认位数位1,无法使用select关键字进行查询,但是可以通过bin() 与hex()函数对数据值进行读取。下面以一个简单的例子演示其使用:
mysql> alter table demo1 add column w bit;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc demo1;
+-------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| x | float | YES | | NULL | |
| y | double | YES | | NULL | |
| z | decimal(10,0) | YES | | NULL | |
| w | bit(1) | YES | | NULL | |
+-------+---------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
mysql> insert into demo1(w) values(1);
Query OK, 1 row affected (0.00 sec)
mysql> select * from demo1;
+-------+-------+------+------+
| x | y | z | w |
+-------+-------+------+------+
| 5.21 | 5.21 | 5 | NULL |
| 1.31 | 1.31 | 1 | NULL |
| 1.315 | 1.315 | 1 | NULL |
| NULL | NULL | NULL | |
+-------+-------+------+------+
4 rows in set (0.00 sec)
正如你上面看到的新增的一行数据w的字段位空什么都看不到,我们在使用bin函数进行查询:
mysql> select w, bin(w) from demo1;
+------+--------+
| w | bin(w) |
+------+--------+
| NULL | NULL |
| NULL | NULL |
| NULL | NULL |
| | 1 |
+------+--------+
4 rows in set (0.00 sec)
MYSQL中时间类型定义的比较多,下面列出了Mysql中日期与时间类型。
类型名称 | 日期格式 | 存储空间 |
---|---|---|
YEAR | YYYY | 1个字节 |
TIME | HH:MM:SS | 3个字节 |
DATE | YYYY-MM-DD | 3个字节 |
DATETIME | YYYY-MM-DD HH:MM:SS | 8个字节 |
TIMESTAMP | YYYY-MM-DD HH:MM:SS | 4个字节 |
DATE、DATETIME、TIMESTAMP 是MYSQL最常用的三种时间类型,下面以简单的例子演示其使用:
mysql> create table timedemo(d date, dt datetime,ts timestamp);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into timedemo values(now(),now(),now());
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> show warnings;
+-------+------+---------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+---------------------------------------------------------------------+
| Note | 1292 | Incorrect date value: '2020-06-10 05:44:51' for column 'd' at row 1 |
+-------+------+---------------------------------------------------------------------+
1 row in set (0.01 sec)
mysql> select * from timedemo;
+------------+---------------------+---------------------+
| d | dt | ts |
+------------+---------------------+---------------------+
| 2020-06-10 | 2020-06-10 05:44:51 | 2020-06-10 05:44:51 |
+------------+---------------------+---------------------+
1 row in set (0.00 sec)
在上面我们使用了now函数插入了当前的日期,其中date类型插入的数据给出了告警信息,但是数据还是能正常插入进表。我们查看表信息如下所示:
mysql> desc timedemo;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+-----------------------------+
| d | date | YES | | NULL | |
| dt | datetime | YES | | NULL | |
| ts | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------+
3 rows in set (0.00 sec)
可以发现系统自动位ts创建了默认值CURRENT_TIMESTAMP,并且设置了not null 和 on update CURRENT_TIMESTAMP。那么我们像ts
这个列插入null查看是否默认插入了当前系统时间如下:
mysql> insert into timedemo(ts) values(null);
Query OK, 1 row affected (0.00 sec)
mysql> select * from timedemo;
+------------+---------------------+---------------------+
| d | dt | ts |
+------------+---------------------+---------------------+
| 2020-06-10 | 2020-06-10 05:44:51 | 2020-06-10 05:44:51 |
| NULL | NULL | 2020-06-12 22:19:38 |
+------------+---------------------+---------------------+
2 rows in set (0.01 sec)
可以很清晰看到ts
的列已经插入到了数据,这里需要注意的是Mysql只会给第一个类型为TimeStamp设置默认值,如果有第二个类型为TimeStamp的列将不会设置为当前时间,我们新增一个列验证一下:
mysql> alter table timedemo add column ts1 timestamp ;
ERROR 1067 (42000): Invalid default value for 'ts1'
我们发现增加新的TimeStamp类型必须为其指定一个默认值,所以我们设置其默认为null
如下:
mysql> alter table timedemo add column ts1 timestamp null;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc timedemo;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+-----------------------------+
| d | date | YES | | NULL | |
| dt | datetime | YES | | NULL | |
| ts | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| ts1 | timestamp | YES | | NULL | |
+-------+-----------+------+-----+-------------------+-----------------------------+
4 rows in set (0.00 sec)
mysql> insert into timedemo(ts1) values(null);
Query OK, 1 row affected (0.00 sec)
mysql> select * from timedemo;
+------------+---------------------+---------------------+------+
| d | dt | ts | ts1 |
+------------+---------------------+---------------------+------+
| 2020-06-10 | 2020-06-10 05:44:51 | 2020-06-10 05:44:51 | NULL |
| NULL | NULL | 2020-06-12 22:19:38 | NULL |
| NULL | NULL | 2020-06-12 22:56:36 | NULL |
+------------+---------------------+---------------------+------+
3 rows in set (0.00 sec)
开发中经常设置的列时间类型为datetime
类型,而不是timestamp
类型。其原因有如下几点:
timestamp
支持的范围时间小,最大时间只能为2038年的某一天,而datetime类型支持的时间范围广最大可以支持到9999年。timestamp
类型的数据插入和查询受到当前时区的影响,如果是其他时区的人看到会有时差。timestamp
类型受到不同Mysql版本影响较大。字符串类型可以存储字符串数据,也可以存储二进制数据。Mysql支持两种字符类型的数据即:文本字符串和二进制字符串。其中文本字符串类型有CHAR、VARCHAR、TEXT、ENUM、SET,下表中列出了MYSQL的文本字符串类型。
类型名称 | 解释说明 | 存储空间 |
---|---|---|
CHAR(M) | 固定长度的文本字符串类型 | 可存储0-255之间的字符长度 |
VARCHAR(M) | 变长的文本字符串类型 | M为0-65535之间的整数,其中值长度为M+1个字节 |
TINYTEXT | 非常小的文本字符串类型 | 存储长度在0-255个字节 |
TEXT | 小的文本字符串类型 | 存储长度为0-65535个字节 |
MEDIUMTEXT | 比TEXT大的文本字符串类型 | 存储长度为0-2^24个字节长度 |
LONGTEXT | 非常大的文本字符串类型 | 可存储0-2^32个字节长度 |
ENUM | 枚举类型 | 1-2个字节,取决于枚举值数目最大65535 |
SET | 一个字符串对象可以有0个或多个SET成员 | 1,2,3,4 最多支持64个成员 |
CHAR(M) 与 VARCHAR(M) 两者都可以存储较短的字符串类型,它们唯一的区别就是:CHAR类型创建时候声明的长度为固定长度,当保存时候右侧会填充空格以达到固定长度的值大小。而VARCHAR的实际长度为实际存储空间长度加一。下面将以一个例子描述两者的区别如下所示:
mysql> create table vcdemo(a char(4), b varchar(4));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into vcdemo values('ab ','ab ');
Query OK, 1 row affected (0.00 sec)
mysql> select length(a),length(b) from vcdemo;
+-----------+-----------+
| length(a) | length(b) |
+-----------+-----------+
| 2 | 4 |
+-----------+-----------+
1 row in set (0.00 sec)
从查询结果可以看到a 在保存’ab '时候将末尾的两个空格删除了,而b字段保留了末尾的两个空格。
Text类型的数据可以存储大量文本字符串,插入数据不会删除尾部空格。一般前端文本框保存大量文本内容时候就可以使用次类型。
ENUM是一个字符串类型,其值为表创建时候在列中规定的枚举值,其语法如下所示:
CREATE TABLE 表名 (列名 ENUM(值1,值2,值3....));
下面一个简单的案列演示其使用:
mysql> create table enumdemo(gender enum('男','女'));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into enumdemo values('男'),('女'),(null),('1');
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> select * from enumdemo;
+--------+
| gender |
+--------+
| 男 |
| 女 |
| NULL |
| 男 |
+--------+
4 rows in set (0.00 sec)
从上面的例子中可以看出,如果插入的数据不是枚举类型中的值也不是null将会默认插入枚举中的第一个值。
SET是一个字符串对象,其与ENUM类型很相似。其语法如下所示:
CREATE TABLE 表名 (列名 SET(值1,值2,值3....))
SET类型与ENUM类型的区别就是:SET类型可以一次选取多个成员而ENUM则最多只能选一个。此外如果插入SET字段中的列值有重复,Mysql会自动将其去重并添加到MYSQL中。下面以一个简单的例子演示其使用:
mysql> create table setdemo( sets set('a','b','c','d'));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into setdemo values('a,b'),('b,b,c'),('c,b,a');
Query OK, 3 rows affected (0.00 sec)
mysql> select * from setdemo;
+-------+
| sets |
+-------+
| a,b |
| b,c |
| a,b,c |
+-------+
3 rows in set (0.00 sec)
从结果可以看到对于set类型如果插入数据重复则只取一个,于此同时插入了不按顺序的值。Mysql会将其转换为自动顺序插入,如上述’c,b,a’插入后显示值为’a,b,c’。
二进制字符串中最常见的就是BINARY,VARBINARY 其类型类似于CHAR、VARCHAR,不同的是这两个类型存储的是二进制字符串,其语法如下所示:
CREATE TABLE 表名 (列名 BINARY(M)| VARBINARY)
BINARY类型的长度是固定的,在指定M长度后如果存储长度不足M长度的,则会在存储内容后填充若干’\0’以将存储内容达到M长度。例如为指定列类型为BINARY(3),当插入’a’时,存储的内容实际为’a\0\0’。
VARBINARY的长度是可变的,指定M长度后,其长度可以在0-M之间,例如为指定列数据类型为VARBINARY(3),当插入’a’时候,其存储内容就是’a’。下面以一个简单的案列演示其使用:
mysql> create table binarydemo(a binary(3),b varbinary(3));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into binarydemo values('5','5');
Query OK, 1 row affected (0.00 sec)
mysql> select length(a),length(b) from binarydemo;
+-----------+-----------+
| length(a) | length(b) |
+-----------+-----------+
| 3 | 1 |
+-----------+-----------+
1 row in set (0.00 sec)
可以看到当插入数据不满最大长度时候,BINARY会填充字符以达到最大长度。
BLOB是一个大的二进制内容存储类型,其存储的是字节字符串,需注意其于TEXT的区别,TEXT存储的是非二进制字符串内容,BLOB分为如下几个类型。
类型名称 | 解释说明 | 存储内容 |
---|---|---|
TINYBLOB | 非常小的BLOB类型 | 存储最大长度为255个字节 |
BLOB | 小的BLOB类型 | 存储最大的长度为65535个字节 |
MEDIUMBLOB | 稍微小的BLOB类型 | 存储最大长度为2^24-1 个字节 |
LONGBLOB | 最大的BLOB类型 | 最大长度为2^ ^2-1个字节 |
MYSQL从5.7.8版本后就新增了JSON类型,之前存储JSON内容我们都是将其保存到VARCHAR或Text类型上。下面以一个简单的例子演示此种数据类型的使用:
mysql> create table jsondemo(content json);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into jsondemo values('{"age":15,"gender":"男","name":"小明"}');
Query OK, 1 row affected (0.00 sec)
mysql> select * from jsondemo;
+------------------------------------------------+
| content |
+------------------------------------------------+
| {"age": 15, "name": "小明", "gender": "男"} |
+------------------------------------------------+
1 row in set (0.00 sec)
MYSQL中提供了很多的数据类型,为了优化存储,提高数据库性能。需要我们清晰了解什么样的业务数据使用最精确的类型,下面将简单总结日常开发中对于数据类型的选择。
如果存储的数值不包括小数部分,则使用整数类型。一般开发中常常使用的整数类型为int,实际可以根据你的业务存储数值大小可选择合适的整型数值类型。
浮点数包括float和double类型,double类型比float类型高,如果对存储浮点型数精度要求较高的情况下可选择double类型。
浮点数比定点数一个优势就是浮点数能存储更大的数,但是由于其精度都没有定点数高,所以日常开发中对于余额、转账金额等精度要求极高的数据存储时候,decimal更能满足我们日常业务需求而无需担心其运算出现的精度损失的问题。
开发中最常见存储的时间类型为timestamp与datetime类型,timestamp存储的时间上限为2038年且其值插入与当前地区有关,所以日常中更多使用的是datetime类型。
我们已经知道char是固定长度存储字符串而varchar是变长的,所以char相对于varchar会占据更多的空间,但是其处理速度比varchar速度快,这就是典型的空间换时间问题。实际开发可以根据业务选择适合的数据类型。
这两个数据类型在开发中使用频率不是很高,enum是一个枚举类型,如果从多个值取出一个值就可以使用枚举。例如:性别字段适合定义枚举类型,因为每个人的性格只能是男、女之间的一个。set可以取多值。
blob是存储二进制字符串,而text是存储非二进制的数据,一般我们使用blob存储图片、音屏等信息,而text存储文本文件。
与char 和 varchar类似,我们知道binary是固定长度的而varbinary是变长的,当存储内容不足的时候binary会为存储的数据后面加入’\0’的内容,所以其占据更大的空间但速度更快。