MySQL:数据类型
数据类型
与其它编程语言类似,在MySQL中,每张表中的每个字段都有它的数据类型。MySQL中的数据类型分为数字类型、字符串类型、地理空间类型、JSON类型和日期时间类型。
数字类型
在MySQL中,数字类型可以分为整数类型和浮点数类型。对于数字类型,可以为其设置UNSIGNED(无符号)
、ZEROFILL(自动填充0)
、UNIQUE(唯一性)
、AUTO_INCREMENT(自动增长列)
、DEFAULT(指定默认值)
、NOT NULL(非空)
进行限制。
整数类型
数据类型 | 字节数 | 有符号 | 无符号 |
---|---|---|---|
TINYINT | 1字节 | 从 -128到127 | 从0到255 |
SMALLINT | 2字节 | 从 -32768到32767 | 从0到65535 |
MEDIUMINT | 3字节 | 从 -8388608到8388607 | 从0到16777215 |
INT | 4字节 | 从 -2147483648到2147483647 | 从0到4294967295 |
BIGINT | 8字节 | 从 -263到263-1 | 从0到264-1 |
使用如下SQL表达式描述一个INT
类型:
INT(5) // 括号中为有效数字长度
浮点数类型
数据类型 | 字节数 | 范围 |
---|---|---|
DECIMAL | 自定义 | 最长有效位数65位 需指定数字精度和小数位数 |
FLOAT | 4或8字节 | (±3.402823466E)+38 |
DOUBLE | 8字节 | (±1.7976931348623157E)+308 (±2.2250738585072014E)-308 |
使用如下SQL表达式描述一个DECIMAL
类型:
DECIMAL(5,2) // 5为数字精度,2为小数位数
注:由于使用
FLOAT
和DOUBLE
会出现数值不精确问题,需要使用浮点数据类型时一定要选DECIMAL
。
超出数值范围的后果
如果插入的数值超出了字段的数值范围,则MySQL会报如下错误:
字符串类型
MySQL中的字符串可以分为三种类型:普通字符串、可变字符串和特殊字符串。
注:普通字符串类型和变长字符串类型的区别是——普通字符串类型的长度不会改变,而不同可变字符串类型的长度不同。例如:可变字符串类型
BLOB
就有TINYBLOB
、MEDIUMBLOB
和LONGBLOB
三种不同的版本,每个版本的最大长度也不同。
普通字符串类型
普通字符串有以下四种类型:CHAR
、VARCHAR
、BINARY
、VARBINARY
。其中CHAR
和VARCHAR
用于存储普通字符串,BINARY
和VARBINARY
用于存储二进制字符串。
CHAR
和BINARY
是定长字符串,即如果字符串长度未达到定义的长度就要使用空格或0x00进行补全。下面的表格说明了CHAR
和VARCHAR
之间的区别:
原值 | CHAR(7) | VARCHAR(7) |
---|---|---|
Liyue | 'Liyue ' (2个空格) |
‘Liyue’ (0个空格) |
Inazuma | ‘Inazuma’ (0个空格) |
‘Inazuma’ (0个空格) |
Mondstadt | ‘Mondsta’ (缺2字符) |
‘Mondsta’ (缺2字符) |
CREATE DATABASE test;
CREATE TABLE IF NOT EXISTS `charlist` (var VARCHAR(7), chr CHAR(7));
INSERT INTO `charlist`(var,chr) VALUES('liyue ','liyue ');
SELECT CONCAT('(',var,')') AS 'VARCHAR',CONCAT('(',chr,')') AS 'CHAR' FROM `charlist`;
注:在通常情况下,MySQL执行SELECT语句时会删除CHAR类型值的追加空格。
下面列出了普通字符串类型的名称和取值范围:
数据类型 | 建议字符串长度 | 注释 |
---|---|---|
CHAR | 255 | 定长 |
VARCHAR | 255 | 变长 |
BINARY | 同上, 但是以字节为单位 |
定长二进制 |
VARBINARY | 同上, 但是以字节为单位 |
变长二进制 |
使用下面的SQL表达式描述一个字符串类型:
VARCHAR(255)
注:如果字符串长度超过255字符,建议使用
TEXT
作为存储数据类型。
可变字符串类型
MySQL中可变字符串类型的特点是最大长度会变化。(即有多个不同长度的相同类型版本)
下面列出了一些常见的可变字符串类型:
数据类型 | 最长字节数 | 解释 |
---|---|---|
TEXT | 65535 | 普通文本类型 |
TINYTEXT | 255 | 缩小版文本类型 |
MEDIUMTEXT | 16777215 | 加长版文本类型 |
LONGTEXT | 232-1 | 超长版文本类型 |
BLOB | 65535 | 普通二进制类型 |
TINYBLOB | 255 | 缩小版二进制类型 |
MEDIUMBLOB | 16777215 | 加长版二进制类型 |
LONGBLOB | 232-1 | 超长版二进制类型 |
注:可变字符串类型通常用于存储一些非常长的数据。如
TEXT
类型可以存储HTML文本,常用于博客、论坛帖子等;BLOB
类型可以用于存储二进制数据,常用于存储音乐、视频、Word甚至可执行文件等。在MySQL中,可变字符串一般不受本表的行长度(65535字节)限制。
使用下面的SQL表达式描述一个可变类型:
BLOB(65535)
特殊字符串
在MySQL中还有两种特殊字符串:ENUM
(枚举类)和SET
(枚举类,可以存入多个值)。
具体可以参考大佬的文章:MySQL中的enum和set类型 - SlowIsFastLemon
地理空间类型
除了几种传统的数据类型,MySQL还支持用于对数学几何关系进行处理的地理空间类型。使用该类型可以便捷地对几何对象(包括点、线、面和各种几何对象的集合)进行查询、运算。
所有MySQL的地理空间类型都是由一个个坐标值组成的,即坐标值在地理空间类型中具有原子性,不可再分。地理空间类型支持DECIMAL
小数类型。
MySQL的地理空间类型分为单值类型和集合类型。下面介绍一些常见的地理空间类型:
单值类型
MySQL中的单值地理空间类型有:GEOMETRY
、POINT
(点)、LINESTRING
(线)、POLYGON
(多边形,即面),其中GEOMETRY
类型是所有地理空间类型的基类。
1.POINT类型
POINT
类型用于表示一个坐标点,经度(X轴)在前,纬度(Y轴)在后,使用空格进行分隔,同一格中有且只有一个坐标值。例如:
POINT(30 10) // 示例值,外面的POINT()不能丢
2.LINESTRING类型
LINESTRING
类型用于表示由多个点组成的一条线段,所以该类型的数据由多个点的坐标值组成,不同坐标值之间用英文逗号分隔,同一格中至少有两个点。例如:
LINESTRING(30 10,32 12,32.2 12.8,32.1 14,31.6 16.2,29 20,22 24,14 25)
3.POLYGON类型
POLYGON
类型用于表示一个几何图形(即面),它由多个点坐标组成,点坐标之间用英文逗号分隔。对于该类型的语法有如下规定:
- POLYGON至少有一个环。
- POLYGON所有的环全部是闭合的。(第一个值与最后一个值相同)
- 每一个环至少有4个点。
- 集合不为空,GeometryCollection类型除外。
POLYGON(16 18,30 20,30 10,20 12,16 18)
集合类型
MySQL地理空间类型的集合类型是各种单值类型(POINT
、LINESTRING
、POLYGON
)的组合。MySQL中有如下集合类型:MULTIPOINT
、MULTILINESTRING
、MULTIPOLYGON
、GEOMETRYCOLLECTION
。
1.MULTIPOINT类型
顾名思义,该类型是多个POINT
类型的集合。多个坐标值之间用逗号分隔。
MULTIPOINT(30 10,50 43,47 9)
2.MULTILINESTRING类型
顾名思义,该类型是多个LINESTRING
类型的集合。每条线段至少要有两个点。
MULTILINESTRING((30 10,60 40),(20 50,60 10))
3.MULTIPOLYGON类型
顾名思义,该类型是POLYGON
类型的集合。该复合类型必须遵守如下语法要求:
- MultiPolygon类型没有两个Polygon元素的内部相交。
- MultiPolygon没有两个Polygon元素交叉或在无数个点处接触。
- MultiPolygon是常规的封闭点集。
- 具有多个Polygon的MultiPolygon内部没有连接。
- MultiPolygon内部的连接组件的数量等于MultiPolygon中的Polygon值的数量。
MULTIPOLYGON(((10 10,20 40,30 30,10 10)),((50 40,60 10,40 30,50 40)))
4.GeometryCollection类型
GeometryCollection
类型是由多个POINT
、LINESTRING
和POLYGON
元素组合起来的复合几何类型,用户可以使用该类型记录复杂的、由点线面等组合的几何图形(例如地形等)。
GEOMETRYCOLLECTION(POINT(40 20),LINESTRING(40 20,50 50),POLYGON((50 50,20 20,80 20,50 50)))
JSON类型
在MySQL 5.7.8之后,MySQL实现了对
JSON
数据类型的存储支持。在存储JSON数据时,可以使用内置的JSON类型而不必使用字符串类型。存储在JSON类型中的数据将转化为MySQL内部的存储格式,还有很多原生函数提供了对JSON数据进行增删改查的功能,极大地方便了数据的提取与存储。
JSON类型又分为字符串、数字、JSON数组和JSON对象。JSON数组是一组以列表形式存储的数据,而JSON对象是以键值对形式存储、有上下级关系的字典。
"Sakana~" // JSON String
1145.14 // JSON Number
[1,2,"3","abcd"] // JSON Array
{
"a":1,"b":2,"c":{
"ab":1,"ac":2},"d":"aaa"} // JSON Object
如果要访问JSON类型中的元素,SQL表达式的语法如下:
- JSON字符串:
字段名->>“$”
- JSON数字:
字段名->“$”
- JSON数组:
字段名->>“$[索引编号]”
- JSON对象:
字段名->>“$.键名”
- JSON多维对象:
字段名->>“$.一维键名.二维键名.N.最后一维键名”
注:JSON路径中的“
$
”符号代表整个JSON数据。
例如:
json1->>"$" // Access JSON String
json1->"$" // Access JSON Number
json1->>"$[0]" // Access JSON Array
json1->>"$.c.ad.bd" // Access JSON Object
日期时间类型
MySQL中有五种日期时间类型:YEAR
、DATE
、TIME
、DATETIME
、TIMESTAMP
。下面介绍它们的取值范围和单位等信息:
数据类型 | 格式 | 取值范围 | 字节数 | 说明 |
---|---|---|---|---|
YEAR | YYYY | 1901 - 2155 | 1 | 只保存年份 |
DATE | YYYY-MM-DD | 1000/01/01 - 9999/12/31 |
3 | 保存年月日 |
TIME | hh:mm:ss | -838:59:59 - 838:59:59 |
3 | 保存时分秒 |
DATETIME | YYYY-MM-DD hh:mm:ss |
1000/01/01 00:00:00 - 9999/12/31 23:59:59 |
8 | 年月日时分秒 |
TIMESTAMP | YYYY-MM-DD hh:mm:ss Time_Zone |
1970/01/01 00:00:01 UTC - 2038/01/19 03:14:07 UTC |
4 | 时间戳 (共2147483647秒) |
如果给日期时间类型赋一个不合法的时间值,那么该值会被0取代。
注:在实际生产环境中,如果一个时间值需要被大量地计算,那么推荐使用
TIMESTAMP
类型;如果该时间值仅是用于被展示的,那么推荐使用DATETIME
类型。
MySQL的行长度限制
在MySQL的数据表中,为了防止一行记录字节数过多导致效率变慢、引发系统错误等一系列问题,MySQL的各种存储引擎对单行记录的定义长度进行了限制,这种限制就叫MySQL行长度限制。
该限制只对以下数据类型生效:
- CHAR
- VARCHAR
- BINARY
- VARBINARY
MySQL的单行长度限制为65535字节。如果一行的定义长度超过了65535字节,MySQL就会报出如下错误:
若想解决该问题,只有以下两种方法:
1. 调小字段长度。
2. 将字段类型变为TEXT
或者BLOB
。
下面举例说明该问题(请先执行SET GLOBAL sql_mode='';
关闭严格模式):
假设我有一个数据库
test
,现在要创建一张表testtbl
表的结构如下所示:
# 第一种情况
CREATE TABLE IF NOT EXISTS `testtbl`(
id INT(5) UNSIGNED UNIQUE AUTO_INCREMENT NOT NULL,
a VARCHAR(10000) DEFAULT NULL, // a字段长度10000字符
b VARCHAR(10000) DEFAULT NULL, // b字段长度10000字符
c VARCHAR(10000) DEFAULT NULL, // c字段长度10000字符
PRIMARY KEY (id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8; // 使用InnoDB存储引擎和utf8字符集
# 第二种情况
CREATE TABLE IF NOT EXISTS `testtbl`(
id INT(5) UNSIGNED UNIQUE AUTO_INCREMENT NOT NULL,
a VARCHAR(30000) DEFAULT NULL, // a字段长度30000字符
b VARCHAR(30000) DEFAULT NULL, // b字段长度30000字符
c VARCHAR(30000) DEFAULT NULL, // c字段长度30000字符
PRIMARY KEY (id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8; // 使用InnoDB存储引擎和utf8字符集
先说结论,第一种情况(每字段1万字符)失败,第二种情况(每字段3万字符)成功。
- 首先我们要知道,一个字符包含几个字节是根据使用的字符集来决定的。在
utf8
字符集中,一个字符包含3个字节。 - 在MySQL的宽松模式中,一个
VARCHAR
字段的定义长度超过65535字节后,会自动转为TEXT
类型。 - MySQL还需要额外的几个字节来存储
VARCHAR
字段的长度。
在第一种情况中,因为每个字段最大定义了10000个字符,采用了utf8
字符集(每个字符3字节),所以每个字段的定义长度为30000个字节,不会被转为TEXT
类型。这样一行的定义长度就是10000\*3\*3=90000字节
,明显超过了65535字节,所以报错。
而在第二种情况中,每个字段定义了30000个字符,采用了utf8
字符集,所以每个字段的定义长度为90000字节,明显超过了单个字段的限制,于是MySQL在非严格模式下会将其转为TEXT
类型(严格模式直接报错),又因为TEXT
类型不受行长度限制,所以会创建成功但抛出警告。
综上,我们可以总结出计算行长度的公式:
行 长 度 > ( 字 段 1 字 符 数 + . . . + 字 段 n 字 符 数 ) ∗ 字 符 集 位 数 行长度>(字段1字符数+...+字段n字符数)*字符集位数 行长度>(字段1字符数+...+字段n字符数)∗字符集位数
下面列出常用字符集的位数:
字符集 | 字符集位数 |
---|---|
Lantin | 1字节 |
GB2312 | 英文字符1字节 非英文字符2字节 |
ASCII | 1字节 |
utf8 | 3字节 |
utf8mb4 | 4字节 |
GB18030 | 4字节 |