MySQL第三章

130 阅读14分钟

第3章 MySQL支持的数据类型

3.1 数值类型:包括整数和小数

数值类型主要用来存储数字,不同的数值类型提供不同的取值范围,可以存储的值范围越大,所需要的存储空间也越大。MySQL支持所有标准SQL中的数值类型,其中包括严格数据类型(INTEGER、SMALLINT、DECIMAL、NUMERIC)和近似数值类型(FLOAT、REAL、DOUBLE PRECISION)。MySQL还扩展了TINYINT、MEDIUMINT和BIGINT等3种不同长度的整数类型,并增加了BIT类型,用来存储位数据。

对于MySQL中的数值类型,还要做如下说明:

  • 关键字INT是INTEGER的同义词。
  • 关键字DEC和FIXED是DECIMAL的同义词。
  • NUMERIC和DECIMAL类型被视为相同的数据类型。
  • DOUBLE视为DOUBLE PRECISION的同义词,并在REAL_AS_FLOAT SQL模式未启用的情况下,将REAL也视为DOUBLE PRECISION的同义词。

1、整数类型

image-20211127205706588.png

说明:

对于整数类型,MySQL还支持在类型名称后面加小括号(M),而小括号中的M表示显示宽度,M的取值范围是(0, 255)。int(M)这个M在字段的属性中指定了unsigned(无符号)和zerofill(零填充)的情况下才有意义。表示当整数值不够M位时,用0填充。如果整数值超过M位但是没有超过当前数据类型的范围时,就按照实际位数存储。当M宽度超过当前数据类型可存储数值范围的最大宽度时,也是以实际存储范围为准。

MySQL8之前,int没有指定(M),默认显示(11)。最多能存储和显示11位整数。从MySQL 8.0.17开始,整数数据类型没有zerofill的情况下不推荐使用显示宽度属性,默认显示int。

#演示整数类型
#创建一个表格,表格的名称“t_int”,
#包含两个字段i1和i2,分别是intint(2)类型
#create table t_int(i1 int,i2 int(2));
create table t_int(
    i1 int,
    i2 int(2)  #没有unsigned zerofill,(2)没有意义
);
​
#查看当前数据库的所有表格
show tables;
show tables from 数据库名;
​
#查看表结构
desc 表名称;
desc t_int;
​
mysql> desc t_int;
+-------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------+------+-----+---------+-------+
| i1    | int  | YES  |     | NULL    |       |
| i2    | int  | YES  |     | NULL    |       |
+-------+------+------+-----+---------+-------+
2 rows in set (0.01 sec)
​
#创建一个表格,表格的名称“t_int2”,
#包含两个字段i1和i2,分别是intint(2)类型
create table t_int2(
    i1 int,
    i2 int(2) unsigned zerofill
);
​
mysql> desc t_int2;
+-------+--------------------------+------+-----+---------+-------+
| Field | Type                     | Null | Key | Default | Extra |
+-------+--------------------------+------+-----+---------+-------+
| i1    | int                      | YES  |     | NULL    |       |
| i2    | int(2) unsigned zerofill | YES  |     | NULL    |       |
+-------+--------------------------+------+-----+---------+-------+
2 rows in set (0.01 sec)
​
#添加数据到表格中
insert into 表名称 values(值列表);
insert into t_int values(1234,1234);
insert into t_int2 values(1234,1234);
​
#查询数据
select * from 表名称;
select * from t_int;
select * from t_int2;
​
#添加数据到表格中
insert into 表名称 values(值列表);
insert into t_int values(1,1);
insert into t_int2 values(1,1);
​
insert into t_int values(12222228854225548778455,12222228854225548778455);
mysql> insert into t_int values(12222228854225548778455,12222228854225548778455);
ERROR 1264 (22003): Out of range value for column 'i1' at row

2、bit类型

bit类型,如果没有指定(M),默认是1位。这个1位,那么表示只能存1位的二进制值。这里(M)是表示二进制的位数。M范围从1到64。

对于位类型字段,之前版本直接使用SELECT语句将不会看到结果,而在MySQL8版本中默认以“0X”开头的十六进制形式显示,可以通过BIN()函数显示为二进制格式。

#演示bit类型,存储二进制,只有01
#创建一个表格
create table t_bit(
    b1 bit,  #没有指定(M),默认是1位二进制
    b2 bit(4) #能够存储4位二进制0000~1111
);
​
#查看表结构
desc t_bit;
​
mysql> desc t_bit;
+-------+--------+------+-----+---------+-------+
| Field | Type   | Null | Key | Default | Extra |
+-------+--------+------+-----+---------+-------+
| b1    | bit(1) | YES  |     | NULL    |       |
| b2    | bit(4) | YES  |     | NULL    |       |
+-------+--------+------+-----+---------+-------+
2 rows in set (0.01 sec)
​
#添加记录
insert into t_bit values(1,1);
​
#查看数据
select * from t_bit;
​
mysql> select * from t_bit;
+------------+------------+
| b1         | b2         |
+------------+------------+
| 0x01       | 0x01       |  #0x开头表示十六进制
+------------+------------+
1 row in set (0.00 sec)
​
#显示二进制值,需要使用bin函数
select bin(b1),bin(b2) from t_bit;
​
mysql> select bin(b1),bin(b2) from t_bit;
+---------+---------+
| bin(b1) | bin(b2) |
+---------+---------+
| 1       | 1       |
+---------+---------+
1 row in set (0.00 sec)
​
#添加记录
insert into t_bit values(2,2);
​
mysql> insert into t_bit values(2,2); 
#values()中是十进制值,需要转为二进制存储,2对应10,超过1位,b1存不下
ERROR 1406 (22001): Data too long for column 'b1' at row 1
​
#添加记录
insert into t_bit values(1,8);
​
#查看数据
select * from t_bit;
​
mysql> select * from t_bit;
+------------+------------+
| b1         | b2         |
+------------+------------+
| 0x01       | 0x01       |
| 0x01       | 0x08       |
+------------+------------+
2 rows in set (0.00 sec)
​
​
#显示二进制值,需要使用bin函数
select bin(b1),bin(b2) from t_bit;
​
mysql> select bin(b1),bin(b2) from t_bit;
+---------+---------+
| bin(b1) | bin(b2) |
+---------+---------+
| 1       | 1       |
| 1       | 1000    |
+---------+---------+
2 rows in set (0.00 sec)
​
#添加记录
insert into t_bit values(1,16); #16的二进制10000
mysql> insert into t_bit values(1,16);
ERROR 1406 (22001): Data too long for column 'b2' at row 1

3、小数类型

MySQL中使用浮点数和定点数来表示小数。浮点数有两种类型:单精度浮点数(FLOAT)和双精度浮点数(DOUBLE),定点数只有DECIMAL。浮点数和定点数都可以用(M,D)来表示。

  • M是精度,表示该值总共显示M位,包括整数位和小数位,对于FLOAT和DOUBLE类型来说,M取值范围为0255,而对于DECIMAL来说,M取值范围为065。
  • D是标度,表示小数的位数,取值范围为0~30,同时必须<=M。

浮点型FLOAT(M,D) 和DOUBLE(M,D)是非标准用法,如果考虑到数据库迁移,则最好不要使用,而且从MySQL 8.0.17开始,FLOAT(M,D) 和DOUBLE(M,D)用法在官方文档中已经明确不推荐使用,将来可能被移除。另外,关于浮点型FLOAT和DOUBLE的UNSIGNED也不推荐使用了,将来也可能被移除。FLOAT和DOUBLE类型在不指定(M,D)时,默认会按照实际的精度来显示。DECIMAL类型在不指定(M,D)时,默认为(10,0),即只保留整数部分。例如,定义DECIMAL(5,2)的类型,表示该列取值范围是-999.99~999.99。如果用户插入数据的小数部分位数超过D位,MySQL会四舍五入处理,但是如果用户插入数据的整数部分位数超过“M-D”位,则会报“Out of range”的错误。

DECIMAL实际是以字符串形式存放的,在对精度要求比较高的时候(如货币、科学数据等)使用DECIMAL类型会比较好。浮点数相对于定点数的优点是在长度一定的情况下,浮点数能够表示更大的数据范围,它的缺点是会引起精度问题。

image-20211127210358326.png

#演示小数类型
#创建表格
create table t_double(
    d1 double,
    d2 double(5,2)  #-999.99~999.99
);
​
#查看表结构
desc t_double;
​
#添加数据
insert into t_double values(2.5,2.5);
​
#查看数据
select * from t_double;
mysql> select * from t_double;
+------+------+
| d1   | d2   |
+------+------+
|  2.5 | 2.50 |#d2字段小数点后不够2位用0补充
+------+------+
1 row in set (0.00 sec)
​
#添加数据
insert into t_double values(2.5526,2.5526);
insert into t_double values(2.5586,2.5586);
​
mysql> select * from t_double;
+--------+------+
| d1     | d2   |
+--------+------+
|    2.5 | 2.50 |
| 2.5526 | 2.55 |#小数点后有截断现象,并且会四舍五入
| 2.5586 | 2.56 |#小数点后有截断现象,并且会四舍五入
+--------+------+
3 rows in set (0.00 sec)
​
​
#添加数据
insert into t_double values(12852.5526,12852.5526);
​
#d2字段整数部分超过(5-2=3)位,添加失败
mysql> insert into t_double values(12852.5526,12852.5526); 
ERROR 1264 (22003): Out of range value for column 'd2' at row 1
​
​
#创建表格
create table t_decimal(
    d1 decimal,  #没有指定(M,D)默认是(10,0)
    d2 decimal(5,2)
);
​
​
#查看表结构
desc t_decimal;
mysql> desc t_decimal;
+-------+---------------+------+-----+---------+-------+
| Field | Type          | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| d1    | decimal(10,0) | YES  |     | NULL    |       |
| d2    | decimal(5,2)  | YES  |     | NULL    |       |
+-------+---------------+------+-----+---------+-------+
2 rows in set (0.01 sec)
​
#添加数据
insert into t_decimal values(2.5,2.5);
​
#查看数据
select * from t_decimal;
mysql> select * from t_decimal;
+------+------+
| d1   | d2   |
+------+------+
|    3 | 2.50 |  #d1字段小数点后截断
+------+------+
1 row in set (0.00 sec)
​
insert into t_decimal values(12852.5526,12852.5526);
​
把小数赋值给整数类型的字段时,会截断小数部分,考虑四舍五入
insert into t_int2 values(1.5,1.5);

3.2 字符串类型

MySQL的字符串类型有CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM、SET等。MySQL的字符串类型可以用来存储文本字符串数据,还可以存储二进制字符串。

文本字符串类型:

image-20211127210547156.png

二进制字符串类型:

image-20211127210608685.png

1、char和varchar

CHAR(M)为固定长度的字符串, M表示最多能存储的字符数,取值范围是0~255个字符,如果未指定(M)表示只能存储1个字符。例如CHAR(4)定义了一个固定长度的字符串列,其包含的字符个数最大为4,如果存储的值少于4个字符,右侧将用空格填充以达到指定的长度,当查询显示CHAR值时,尾部的空格将被删掉。

create table temp(
    c1 char,
    c2 char(3)
);
insert into temp values('男','女');#成功
​
insert into temp values('哈哈哈','哈哈哈');#失败
ERROR 1406 (22001): Data too long for column 'c1' at row 1insert into temp values('男','哈哈哈');#成功

VARCHAR(M)为可变长度的字符串,M表示最多能存储的字符数,M的范围由最长的行的大小(通常是65535)和使用的字符集确定。例如utf8mb4字符编码单个字符所需最长字节值为4个字节,所以M的范围是[0, 16383]。而VARCHAR类型的字段实际占用的空间为字符串的实际长度加1或2个字节,这1或2个字节用于描述字符串值的实际字节数,即字符串值在[0,255]个字节范围内,那么额外增加1个字节,否则需要额外增加2个字节。

create table temp(
    name varchar  #错误
);
create table temp(
    name varchar(3)  #最多不超过3个字符
);
insert into temp values('哈哈哈');
​
insert into temp values('哈哈哈哈哈');#ERROR 1406 (22001): Data too long for column 'name' at row 1insert into temp values('好');
drop table temp;
create table temp(
    name varchar(65535)
);
#ERROR 1074 (42000): Column length too big for column 'name' (max = 21845); use BLOB or TEXT instead
因为当前的表是UTF8,一个汉字占3个字节

image-20211127210826463.png

例如,身份证号、手机号码、QQ号、用户名username、密码password、银行卡号等固定长度的文本字符串适合使用CHAR类型,而评论、朋友圈、微博不定长度的文本字符串更适合使用VARCHAR类型。

另外,存储引擎对于选择CHAR和VARCHAR是有影响的。

  • 对于MyISAM存储引擎,最好使用固定长度的数据列代替可变长度的数据列。这样可以使整个表静态化,从而使数据检索更快,用空间换时间。
  • 对于InnoDB存储引擎,使用可变长度的数据列,因为InnoDB数据表的存储格式不分固定长度和可变长度,因此使用CHAR不一定比使用VARCHAR更好,但由于VARCHAR是按照实际的长度存储的,比较节省空间,所以对磁盘I/O和数据存储总量比较好。

2、Enum和Set类型

无论是数值类型、日期类型、普通的文本类型,可取值的范围都非常大,但是有时候我们指定在固定的几个值范围内选择一个或多个,那么就需要使用ENUM枚举类型和SET集合类型了。比如性别只有“男”或“女”;上下班交通方式可以有“地铁”、“公交”、“出租车”、“自行车”、“步行”等。枚举和集合类型字段声明的语法格式如下:

字段名ENUM(‘值1’,‘值2’,…‘值n’)

字段名 SET(‘值1’,‘值2’,…‘值n’)

ENUM类型的字段在赋值时,只能在指定的枚举列表中取值,而且一次只能取一个。枚举列表最多可以有65535个成员。ENUM值在内部用整数表示,每个枚举值均有一个索引值, MySQL存储的就是这个索引编号。例如,定义ENUM类型的列(‘first’, ‘second’, ‘third’)。

image-20211127211743925.png

SET类型的字段在赋值时,可从定义的值列表中选择1个或多个值的组合。SET列最多可以有64个成员。SET值在内部也用整数表示,分别是1,2,4,8……,都是2的n次方值,因为这些整数值对应的二进制都是只有1位是1,其余是0。

image-20211127211806889.png

演示枚举类型:

create table temp(
    gender enum('男','女'),
    hobby set('睡觉','打游戏','泡妞','写代码')
);
insert into temp values('男','睡觉,打游戏'); #成功
​
insert into temp values('男,女','睡觉,打游戏'); #失败
#ERROR 1265 (01000): Data truncated for column 'gender' at row 1insert into temp values('妖','睡觉,打游戏');#失败
ERROR 1265 (01000): Data truncated for column 'gender' at row 1insert into temp values('男','睡觉,打游戏,吃饭');
ERROR 1265 (01000): Data truncated for column 'hobby' at row 1
#文本类型中的枚举和集合
#枚举:固定的几个字符串值,从中选择一个
#集合:固定的几个字符串值,从中选择任意几个
​
create table t_enum_set(
    gender enum('男','女'),
    hobby set('游戏','睡觉','打代码','运动')
);
​
#查看表结构
desc t_enum_set;
​
mysql> desc t_enum_set;
+--------+------------------------------------+------+-----+---------+-------+
| Field  | Type                               | Null | Key | Default | Extra |
+--------+------------------------------------+------+-----+---------+-------+
| gender | enum('男','女')                    | YES  |     | NULL    |       |
| hobby  | set('游戏','睡觉','打代码','运动') | YES  |     | NULL    |       |
+--------+------------------------------------+------+-----+---------+-------+
2 rows in set (0.01 sec)
​
​
#添加数据
insert into t_enum_set
values('男','游戏');
​
#查看数据
select * from t_enum_set;
​
#添加数据
insert into t_enum_set
values('男,女','游戏,睡觉');
​
mysql> insert into t_enum_set
    -> values('男,女','游戏,睡觉');
ERROR 1265 (01000): Data truncated for column 'gender' at row 1
​
#添加数据
insert into t_enum_set
values('男','游戏,睡觉');
​
#添加数据
insert into t_enum_set
values('妖','游戏,睡觉');
mysql> insert into t_enum_set
    -> values('妖','游戏,睡觉');
ERROR 1265 (01000): Data truncated for column 'gender' at row 1
​
#添加数据
insert into t_enum_set
values('男','游戏,睡觉,做饭');
mysql> insert into t_enum_set
    -> values('男','游戏,睡觉,做饭');
ERROR 1265 (01000): Data truncated for column 'hobby' at row 1
​
​
insert into t_enum_set
values(2, 2);
​
mysql> select * from t_enum_set;
+--------+-----------+
| gender | hobby     |
+--------+-----------+
| 男     | 游戏      |
| 男     | 游戏,睡觉 |
| 女     | 睡觉      |
+--------+-----------+
3 rows in set (0.00 sec)
​
​
insert into t_enum_set
values(2, 5);
#5 可以看出 14的组合,0000101000101
​
​
insert into t_enum_set
values(2, 7);
mysql> select * from t_enum_set;
+--------+------------------+
| gender | hobby            |
+--------+------------------+
| 男     | 游戏             |
| 男     | 游戏,睡觉        |
| 女     | 睡觉             |
| 女     | 游戏,打代码      |
| 女     | 游戏,睡觉,打代码 |
+--------+------------------+
5 rows in set (0.00 sec)
​
insert into t_enum_set
values(2, 15);
mysql> select * from t_enum_set;
+--------+-----------------------+
| gender | hobby                 |
+--------+-----------------------+
| 男     | 游戏                  |
| 男     | 游戏,睡觉             |
| 女     | 睡觉                  |
| 女     | 游戏,打代码           |
| 女     | 游戏,睡觉,打代码      |
| 女     | 游戏,睡觉,打代码,运动 |
+--------+-----------------------+
6 rows in set (0.00 sec)
​
​
insert into t_enum_set
values(2, 25);
mysql> insert into t_enum_set
    -> values(2, 25);
ERROR 1265 (01000): Data truncated for column 'hobby' at row 1

3、BINARY和VARBINARY类型

BINARY和VARBINARY类似于CHAR和VARCHAR,只是它们存储的是二进制字符串。

BINARY (M)为固定长度的二进制字符串,M表示最多能存储的字节数,取值范围是0~255个字节,如果未指定(M)表示只能存储1个字节。例如BINARY (8),表示最多能存储8个字节,如果字段值不足(M)个字节,将在右边填充'\0'以补齐指定长度。

VARBINARY (M)为可变长度的二进制字符串,M表示最多能存储的字节数,总字节数不能超过行的字节长度限制65535,另外还要考虑额外字节开销,VARBINARY类型的数据除了存储数据本身外,还需要1或2个字节来存储数据的字节数。VARBINARY类型和VARCHAR类型一样必须指定(M),否则报错。

#演示二进制字符串类型binaryvarbinary
#创建表格
create table t_binary(
    b1 binary, #没有指定(M),默认是(1)
    b2 varbinary #没有指定(M),报错,必须指定(M)
);
ERROR 1064 (42000): You have an error in your SQL syntax; 
check the manual that corresponds to your MySQL server 
version for the right syntax to use near ')' at line 4
​
​
create table t_binary(
    b1 binary, #默认(1),最多能存储一个字节
    b2 binary(6), #最多能存储6个字节,不够6个用\u0000补全
    b3 varbinary(6) #(6),最多能存储6个字节
);
​
#查看表结构
desc t_binary;
​
mysql> desc t_binary;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| b1    | binary(1)    | YES  |     | NULL    |       |
| b2    | binary(6)    | YES  |     | NULL    |       |
| b3    | varbinary(6) | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
​
​
#添加数据
insert into t_binary
values('a','a','a');
​
#查看数据
select * from t_binary;
#显示16进制形式的值
​
mysql> select * from t_binary;
+------------+----------------+------------+
| b1         | b2             | b3         |
+------------+----------------+------------+
| 0x61       | 0x610000000000 | 0x61       |
+------------+----------------+------------+
1 row in set (0.00 sec)
​
#'a'的编码值是97(十进制),对应十六进制(61)
#0x610000000000 补够6个字节
​
#添加数据
insert into t_binary
values('哈','哈','哈');
​
mysql> insert into t_binary
    -> values('哈','哈','哈');
ERROR 1406 (22001): Data too long for column 'b1' at row 1
#'尚'无论在GBK还是UTF8编码下都不可能是1个字节
​
#添加数据
insert into t_binary
values('a','哈哈哈','哈哈哈');
​
mysql> select * from t_binary;
+------------+----------------+----------------+
| b1         | b2             | b3             |
+------------+----------------+----------------+
| 0x61       | 0x610000000000 | 0x61           |
| 0x61       | 0xC9D0B9E8B9C8 | 0xC9D0B9E8B9C8 |  #此时客户端是GBK,哈哈哈编码为6个字节
+------------+----------------+----------------+
2 rows in set (0.00 sec)
​
#添加数据
insert into t_binary
values('a','很开心真好','今天天气真的真好');
​
mysql> insert into t_binary
    -> values('a','很开心真好','今天天气真的很好');
ERROR 1406 (22001): Data too long for column 'b2' at row 1