目录
1. MySQL数据类型分类
使用MySQL数据库存储数据时,不同的数据类型决定了 MySQL存储数据方式的不同。为此,MySQL数据库提供了多种数据类型,其中包括整数类型、浮点数类型、定点 数类型、日期和时间类型、字符串类型、二进制…等等数据类型。
首先看看MySQL数据类型的作用:
- 决定了存储数据时应该开辟的空间大小。
- 决定了如何识别一个特定的二进制序列。
- 决定了数据的取值范围。
1.1 类型汇总
以下是数值类型:
BIT(M) (bit) | 位类型:M指定位数,默认值为1,范围为1-64 |
BOOL (bool) | 布尔类型:使用1表示真,使用0表示假 |
TINYINT [UNSIGNED](tinyint) | 占用1字节,默认为有符号 |
SMALLINT [UNSIGNED] (smallint) | 占用2字节,默认为有符号 |
MEDIUMINT [UNSIGNED] (mediumint) | 占用3字节,默认为有符号 |
INT [UNSIGNED] (int) | 占用4字节,默认为有符号 |
BIGINT [UNSIGNED] (bigint) | 占用8字节,默认为有符号 |
FLOAT[(M,D)] [UNSIGNED] (float) | M指定显示长度,D指定小数位数,占用4字节 |
DOUBLE[(M,D)] [UNSIGNED] (double) | M指定显示长度,D指定小数位数,占用8字节 |
DECIMAL(M,D) [UNSIGNED] (decimal) | M指定显示长度,D指定小数位数,每4个字节表示9个数字,小数点占用1字节 |
以下是文本、二进制类型:
CHAR(L) (char) | 固定长度字符串:L指定字符串长度,最大为255 |
VARCHAR(L) (varchar) | 可变长度字符串:L指定字符串长度上限,最多占用65535字节 |
BLOB (blob) | 用于存储二进制数据 |
TEXT (text) | 用于存储大文本数据 |
以下是时间日期类型:
DATE / DATETIME (date / datetime) | 日期类型:YYYY-MM-DD格式 / YYYY-MM-DD HH:MM:SS格式 |
TIMESTAMP (timestamp) | 时间戳:以YYYY-MM-DD HH:MM:SS格式进行显示 |
以下是字符串类型:
ENUM (enum) | 枚举类型:ENUM类型的取值范围需要在定义字段时进行指定,设置字段值时只允许从成员中选取单个值,其所需的存储空间由定义ENUM类型时指定的成员个数决定 |
SET (set) | 集合类型:SET类型的取值范围需要在定义字段时进行指定,设置字段值时可以从成员中选取一个或多个值,其所需的存储空间由定义SET类型时指定的成员个数决定 |
1.2 整数类型
根据数值取值范围的不同MySQL 中的整数类型可分为5种,分别是TINYINT(tinyint)、SMALUNT(smalunt)、MEDIUMINT(medium)、INT(int)和 BIGINT(bigint)。下图列举了 MySQL不同整数类型所对应的字节大小和取值范围而最常用的为INT类型的,
数据类型 | 字节数 | 无符号数的取值范围 | 有符号数的取值范围 |
---|---|---|---|
TINYINT(tinyint) | 1 | 0~255 | -128~127 |
SMALLINT (smalunt) | 2 | 0~65535 | -32768~32768 |
MEDIUMINT(medium) | 3 | 0~16777215 | -8388608~8388608 |
INT (int) | 4 | 0~4294967295 | -2147483648~ 2147483648 |
BIGINT (bigint) | 8 | 0~18446744073709551615 | -9223372036854775808~9223372036854775808 |
1.3 浮点数类型和定点数类型
在MySQL数据库中使用浮点数和定点数来存储小数。浮点数的类型有两种:单精度浮点数类型(FLOAT)和双精度浮点数类型(DOUBLE)。而定点数类型只有一种即DECIMAL类型。下图列举了 MySQL中浮点数和定点数类型所对应的字节大小及其取值范围:
数据类型 | 字节数 | 有符号的取值范围 | 无符号的取值范围 |
---|---|---|---|
FLOAT (float) | 4 | -3.402823466E+38~-1.175494351E-38 | 0和1.175494351E-38~3.402823466E+38 |
DOUBLE (double) | 8 | -1.7976931348623157E+308~2.2250738585072014E-308 | 0和2.2250738585072014E-308~1.7976931348623157E+308 |
DECIMAL(M,D) (decimal) | M+2 | -1.7976931348623157E+308~2.2250738585072014E-308 | 0和2.2250738585072014E-308~1.7976931348623157E+308 |
从上图中可以看出:DECIMAL类型的取值范围与DOUBLE类型相同。但是,请注意:DECIMAL类型的有效取值范围是由M和D决定的。其中,M表示的是数据的长 度,D表示的是小数点后的长度。比如,将数据类型为DECIMAL(6,2)的数据6.5243 插入数据库后显示的结果为6.52。
1.4 字符串类型和文本类型
在MySQL中常用CHAR 和 VARCHAR 表示字符串。两者不同的是:VARCHAR存储可变长度的字符串。当数据为CHAR(M)类型时,不管插入值的长度是实际是多少它所占用的存储空间都是M个字节;而VARCHAR(M)所对应的数据所占用的字节数为实际长度加1
插入值 | CHAR(3) | 存储需求 | VARCHAR(3) | 存储需求 |
---|---|---|---|---|
‘’ | ‘’ | 3个字节 | ‘’ | 1个字节 |
‘a’ | ‘a’ | 3个字节 | ‘a’ | 2个字节 |
‘ab’ | ‘ab’ | 3个字节 | ‘ab’ | 3个字节 |
‘abc’ | ‘abc’ | 3个字节 | ‘abc’ | 4个字节 |
‘abcd’ | ‘abc’ | 3个字节 | ‘abcd’ | 5个字节 |
文本类型用于表示大文本数据,例如,文章内容、评论、详情等,它的类型分为如下4种:
数据类型 | 储存范围 |
---|---|
TINYTEXT (tinytext) | 0~255字节 |
TEXT (text) | 0~65535字节 |
MEDIUMTEXT (mediumtext) | 0~16777215字节 |
LONGTEXT (longtext) | 0~4294967295字节 |
1.5 日期与时间类型
MySQL提供的表示日期和时间的数据类型分别是 :YEAR、DATE、TIME、DATETIME 和 TIMESTAMP。下图列举了日期和时间数据类型所对应的字节数、取值范围、日期格式以及零值:
数据类型 | 字节数 | 取值范围 | 日期格式 | 零值 |
---|---|---|---|---|
YEAR (year) | 1 | 1901~2155 | YYYY | 0000 |
DATE (date) | 4 | 1000-01-01~9999-12-31 | YYYY-MM-DD | 0000-00-00 |
TIME (time) | 3 | -838:59:59~ 838:59:59 | HH:MM:SS | 00:00:00 |
DATETIME (datetime) | 8 | 1000-01-01 00:00:00~9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 0000-00-00 00:00:00 |
TIMESTAMP (timestamp) | 4 | 1970-01-01 00:00:01~2038-01-19 03:14:07 | YYYY-MM-DD HH:MM:SS | 0000-00-00 00:00:00 |
TIME类型用于表示时间值,它的显示形式一般为HH:MM:SS,其中,HH表示小时, MM表示分,SS表示秒。在MySQL中,可以使用以下3种格式指定TIME类型的值。
1、以’D HH:MM:SS’字符串格式表示。其中,D表示日可取0—34之间的值, 插入数据时,小时的值等于(DX24+HH)。例如,输入’2 11:30:50’插入数据库中的日期为59:30:50。
2、以’HHMMSS’字符串格式或者HHMMSS数字格式表示。 例如,输入’115454’或115454,插入数据库中的日期为11:54:54
3、使用CURRENT_TIME或NOW()输入当前系统时间。
DATETIME类型
DATETIME类型用于表示日期和时间,它的显示形式为’YYYY-MM-DD HH: MM:SS’,其中,YYYY表示年,MM表示月,DD表示日,HH表示小时,MM表示分,SS 表示秒。在MySQL中,可以使用以下4种格式指定DATETIME类型的值。
以’YYYY-MM-DD HH:MM:SS’或者’YYYYMMDDHHMMSS’字符串格式表示的日期和时间,取值范围为’1000-01-01 00:00:00’—‘9999-12-3 23:59:59’。例如,输入’2019-01-22 09:01:23’或 ‘20140122_0_90123’插入数据库中的 DATETIME 值都为 2019-01-22 09:01:23。
1、以’YY-MM-DD HH:MM:SS’或者’YYMMDDHHMMSS’字符串格式表示的日期和时间,其中YY表示年,取值范围为’00’—‘99’。与DATE类型中的YY相同,‘00’— '69’范围的值会被转换为2000—2069范围的值,‘70’—'99’范围的值会被转换为1970—1999范围的值。
2、以YYYYMMDDHHMMSS或者YYMMDDHHMMSS数字格式表示的日期 和时间。例如,插入20190122090123或者190122090123,插入数据库中的DATETIME值都 为 2019-01-22 09:01:23。
3、使用NOW来输入当前系统的日期和时间。
TIMESTAMP类型
TIMESTAMP类型用于表示日期和时间,它的显示形式与DATETIME相同但取值范围比DATETIME小。在此,介绍几种TIMESTAMP类型与DATATIME类型不同的形式:
1、使用CURRENT_TIMESTAMP输入系统当前日期和时间。
2、输入NULL时系统会输入系统当前日期和时间。
3、无任何输入时系统会输入系统当前日期和时间。
1.6 二进制类型
在MySQL中常用BLOB存储二进制类型的数据,例如:图片、PDF文档等。BLOB类型分为如下四种:
数据类型 | 储存范围 |
---|---|
TINYBLOB | 0~255字节 |
BLOB | 0~65535字节 |
MEDIUMBLOB | 0~16777215字节 |
LONGBLOB | 0~4294967295字节 |
2. 有代表的类型测试
2.1 tinyint类型
有符号tinyint范围测试:创建一个表,表当中包含一个tinyint类型的列,默认其为有符号类型。如下:
由于tinyint类型占用1字节,因此有符号tinyint的取值范围为-128~127,插入该范围内的数据时都能成功插入。如下:
如果插入的数据不在-128~127范围内,那么插入数据时就会产生报错。如下:
无符号tinyint范围测试:创建一个表,表当中包含一个tinyint类型的列,并指定其为无符号类型。如下:
由于tinyint类型占用1字节,因此无符号tinyint的取值范围为0~255,插入该范围的数据时都能成功插入。如下:
如果插入的数据不在0~255范围内,那么插入数据时就会产生报错。如下:
除非场景要求数值类型必须是无符号,否则尽量不要使用无符号,因为有符号的数值类型存不下的数据,其对应的无符号类型同样可能存不下,这时应该直接将数值类型进行提升。(不过有一些数据应该是无符号的也建议用无符号,比如年龄等,因为使用无符号和小字节的数据类型一样可以节省空间,虽然只能节省一点,但在大量数据的时候还是能节省不少空间的。)
2.2 bit类型
bit类型的显示方式测试:创建一个表,表当中包含一个int类型的id列和一个8位bit类型的a列。如下:
向表中插入一条记录,记录中指定id和a的值均为10,插入记录后查看表会发现a的值显示的并不是10。如下:
根本原因是因为bit类型在显示时,是按照ASCII码对应的值进行显示的,而在ASCII码表中10对应的是控制字符LF,表示换行的意思。如果向表中插入记录时指定id和a的值均为65,由于ASCII码表中65对应的是字符A,因此插入记录后查看表就会发现a的值显示的是A。如下:
bit类型的范围测试:创建一个表,表当中包含用户名name和用户性别gender,其中gender的类型可以指定为1位bit类型,因为性别只有男和女两种取值,使用1个比特位来表示用户的性别就可以节省空间。如下:
如果规定gender列插入0表示男,插入1表示女,那么在插入用户信息时就可以通过插入0和1来指定用户的性别。如下:
如果插入gender列的数据不是0或1,那么插入数据时就会产生报错。如下:
虽然MySQL提供了位类型bit,但一般不建议将数据类型设置成位类型,除非将来这个数据本身就只是给程序看的,并且数据本身非常占用资源。
因为查询位类型数据时,默认会按照ASCII码对应的值进行显示,这对于将来数据库管理员维护数据库或程序员调试程序都是不太方便的。
2.3 float类型
有符号float范围测试:创建一个表,表当中包含一个float(4,2)类型的列,默认其为有符号类型。如下:
由于float(4,2)的取值范围为-99.99~99.99,因此插入该范围内的数据都能成功插入。如下:
此外,由于MySQL在保存值时会进行四舍五入,因此实际可插入float(4,2)的范围为-99.994~99.994,如果插入的数据不在该范围内,那么插入数据时就会产生报错。如下:
有符号float范围测试:创建一个表,表当中包含一个float(4,2)类型的列,并指定其为无符号类型。如下:
无符号float类型的取值范围,实际就是把对应有符号float类型中的负数部分拿走了,因此float(4,2)的取值范围为0~99.99,实际可插入的范围是0~99.994。如下:
如果插入的数据不在0~99.994范围内,那么插入数据时就会产生报错。如下:
2.4 decimal类型
decimal和float类型的使用方式一样,但decimal的精度比float更高。创建一个表,表当中分别包含一个float(10,8)的列和一个decimal(10,8)的列。如下:
向表当中插入一条记录,指定float和decimal的值均为23.12345612,但最终查表时会发现decimal保持了数据的原貌,而float则会存在一定的精度损失。如下:
2.5 char和varchar类型
char类型测试:创建一个表,表当中包含一个char(6)的content列。如下:
由于char(6)中最多可存储6个字符,因此只要插入的字符个数不超过6个都是能够成功插入的:
如果插入的字符个数超过了6个,那么在插入数据时就会产生报错。如下:
需要注意的是,这里所说的字符并不只是指一个英文字母,MySQL中一个汉字也是一个字符,因此只要插入的汉字个数不超过6个也是可以插入的。
这样的好处是在不同编码中,一个字符所占的字节个数是不同的,比如utf8中一个字符占3个字节,而gbk中一个字符占2个字节。MySQL限定字符的概念不是字节,这样用户就不用关心复杂的编码细节了。
varchar类型测试:创建一个表,表当中包含一个varchar(6)的content列。如下:
由于varchar(6)中最多可存储6个字符,因此只要插入的字符个数不超过6都是能够成功插入的。如果插入的字符个数超过了6个,那么在插入数据时就会产生报错。如下:
varchar类型最多占用65535字节,其中有1~2字节用来表示实际数据长度,还有1字节来存储其他控制信息,因此varchar类型的有效字节数最多是65532字节。
而varchar类型可指定的字符个数上限,与表的编码格式有关:
- 对于utf8编码来说,一个字符占用三个字节,因此varchar(L)中的L最大可指定为 65532 ÷ 3 = 21844
- 对于gbk编码来说,一个字符占用两个字节,因此varchar(L)中的L最大可指定为 65532 ÷ 2 = 32766
因此在定义编码格式为utf8的表时,varchar(L)中的L如果超过了21844,则会产生报错。如下:
而在定义编码格式为gbk的表时,varchar(L)中的L如果超过了32766,则会产生报错。如下:
char和varchar比较:
char和varchar的区别如下:
- char类型可存储字符上限为255,varchar类型可存储字符上限与表的编码格式有关。
- char(L)定义后,无论存储的字符串长度是否到达L,都会开辟用于存储L个字符的定长空间,如果存储的字符串长度超过L则会报错。
- varchar(L)定义后,会根据存储字符串的长度按需开辟空间,并且需要使用1-3字节的空间用于表示存储字符串的长度以及其他控制信息,如果存储的字符串长度超过L则会报错。
如何选取char和varchar类型?
char和varchar的优缺点如下:
- char类型的数据是定长的,因此磁盘空间比较浪费,但是效率高(直接访问定长的空间)。
- varchar类型的数据是变长的,因此磁盘空间比较节省,但是效率低(需要先读取存储字符串的长度,再访问指定长度的空间)。
如果要存储的数据是定长的,那就使用char类型进行存储,比如身份证号码、手机号码等。如果要存储的数据是变长的,那就使用varchar类型进行存储,比如名字、地址等。
2.6 时间日期类型测试
常用的三种时间日期类型如下:
- date:日期格式为YYYY-MM-DD,占用三字节。
- datetime:时间日期格式为YYYY-MM-DD HH:MM:SS,占用八字节。
- timestamp:时间戳,格式为YYYY-MM-DD HH:MM:SS,占用四字节。
创建一个表,表当中包含date、datetime和timestamp三种时间日期类型的列。如下:
查看表结构可以看到,timestamp类型的t3列是不允许为空的,它的默认值为CURRENT_TIMESTAMP(current_timestamp)。如下:
因此如果插入数据时不插入t3列,那么就会自动插入当前的时间戳。如下:
timestamp类型使用场景:创建一个评论表,表当中包含评论人的昵称、评论的内容和评论的发布时间。如下:
向评论表中插入记录时,只需要指明评论人的昵称和评论的内容,评论的发布时间默认会设置成该记录的插入时间。如下:
如果评论人修改了评论内容,那么就需要对评论表进行更新,更新表的同时评论的发布时间也会更新为修改表的时间。如下:
2.7 enum和set类型
enum和set类型的区别如下:
- 在定义enum字段时需要提供若干个选项的值,在设置enum字段值时只允许选取其中的一个值。
- 在定义set字段时需要提供若干个选项的值,在设置set字段值时可以选取其中的一个或多个值。
比如人的性别只能从男和女中进行二选一,因此可以定义成enum类型,而人的爱好在提供的选项中可能存在多个,因此可以定义成set类型。
创建一个调查表,表当中包含被调查人的姓名、性别和爱好。如下:
向表中插入记录时,被调查人的性别只能从男和女中进行二选一,被调查人的爱好可以从提供的若干个选项中进行多选一或多选多,多个爱好之间需要通过英文逗号隔开。如下:
通过数字设置enum:在插入记录时,除了通过指明男女来设置性别,还可以通过插入数字1和2来设置性别。如下:
根本原因在于,MySQL出于效率考虑,在存储enum值时实际存储的都是数字,enum中提供的选项值依次对应数字1、2、3、…,最多65535个,因此在设置enum值时可以通过数字的方式进行设置。
通过数字设置set:在插入记录时,除了通过指明多个选项来设置爱好,还可以通过数字的方式来设置。如下:
因为MySQL存储set值时实际存储的也是数字,set中提供的选项值依次对应数字1、2、4、8、…,最多64个,因此在设置set值时可以通过数字的方式进行设置。
虽然enum和set可以通过数字的方式进行设置,但严重不推荐这种做法,因为这样的SQL可读性太差,导致后期维护成本变高。
测试enum和set查找:如果想要筛选出调查表中所有女同志的信息,那么直接在筛选时指明gender='女'即可,因为enum类型的值只能多选一。如下:
但如果要筛选出调查表中爱好包含敲代码的人的信息就比较麻烦了,如果继续使用上述方式,那么最终筛选出来的是爱好仅为敲代码的人的信息。如下:
这时需要借助find_in_set(str,strlist)函数,该函数的作用是查询strlist中是否包含str,如果包含则返回str在strlist中的位置(从1开始),否则返回0。
通过select可以对find_in_set函数进行验证,依次查找集合a,b,c中是否包含字符a、b、d,这时在查找字符a和b时就会得到其在集合中的下标,而在查找字符d时就会得到0值。如下:
这时就可以通过select搭配find_in_set函数,来筛选出爱好包含敲代码的人的信息了。如下:
此外,我们还可以继续添加筛选条件,比如筛选出爱好中包含敲代码,但爱好又不仅仅只有敲代码的人的信息(<>是不等于的意思)。如下:
本篇完。
下篇内容是MySQL表的约束。