内容来自《MySQL从入门到精通》清华大学出版社一书的内容,随看书随打打笔记,会不断补充
介绍:整数类型,浮点数类型和定点数类型,日期与时间类型,字符串类型,二进制类型
5.1.1整数类型
类型名称 | 说明 | 存储需求 |
---|---|---|
TINYINT | 很小的整数 | 1个字节 |
SMALLINT | 小的整数 | 2个字节 |
MEDIUMINT | 中等大小的整数 | 3个字节 |
INT(INTEGERE) | 普通大小的整数 | 4个字节 |
BIGINT | 大整数 | 8个字节 |
怎么计算,以TINYINT为例,占用1个字节(8bit),无符号的最大数值2的8次方-1,即255。有符号的最大值为2的7次方-1,即127。
类型名称 | 有符号 | 无符号 |
---|---|---|
TINYINT | -128~127 | 0~255 |
SMALLINT | -32768~32767 | 0~65535 |
MEDIUMINT | -8388608~8388607 | 0~16777215 |
INT(INTEGERE) | -2147483648~2147483647 | 0~4294967295 |
BIGINT | -9223372036854775808~9223372036854775807 | 0~1844644073709551615 |
year int(4)
在这里,在year里的数据一般只显示4位数字的宽度。
显示宽度和数据类型的取值范围是无关的。显示宽度只是知名MySQL最大可能显示的数字个数,数值的位数小于指定的宽度时会由空格填充,如果插入了大于显示宽度的值,只要该值不超过该类型整数的取值范围,数值仍会插入,而且能够显示出来。例如,在year中插入数据19999,五位的数据通过SELECT语句查询后,仍将完整显示19999,而不是1999。
例子:创建一个表,查看系统默认添加的宽度
CREATE TABLE tmp1
(
x TINYINT,
y SMALLINT,
z MEDIUMINT,
m INT,
n BIGINT
);
以TINYINT为例,-128~127,符号占一位数字位,因此显示宽度为4。
显示宽度只用于显示,并不能限制取值范围和占用空间。如:int(3)会占用4个字节的存储空间,并且允许的最大值也不为999,而是int整性所允许的最大值。
5.1.2浮点数类型和定点数类型
MySQL中使用浮点数和定点数来表示小数。
浮点类型:FLOAT、DOUBLE。
定点类型:DECIMAL。
浮点类型和定点类型都可以用(M,N)来表示,其中M称为精度,表示总共的位数;N称为标度,是表示小数的位数。
类型名称 | 说明 | 存储要求 |
---|---|---|
FLOAT | 单精度浮点数 | 4个字节 |
DOUBLE | 双精度浮点数 | 8个字节 |
DECIMAL (M,N),DEC | 压缩的“严格”定点数 | M+2个字节 |
DECIMAL 与另两个不同,它是以串来存放的,DECIMAL 可能的最大取值范围与DOUBLE一样,但是其有效的取值范围由M和N的值决定,如果改变M而固定N,其取值范围将会随M的变大而变大。
float:1bit(符号位)+8bits(指数位+23bits(尾数位)
double:1bit(符号位)+ 11bits(指数位)+ 52bits(尾数位)
float和double的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。
为此:
float:2^23 = 8388608,共七位,意味着最多能有7位有效数字,但绝对能保证的为6位,也即float的精度为6~7位有效数字;
double:2^52 = 4503599627370496,一共16位,同理,double的精度为15~16位。
无论是定点还是浮点类型,如果用户指定的精度超出精度范围,则会四舍五入进行处理。
例子:查看三种类型系统给定的精度
创建表tmp2,其中字段x、y、z数据类型依次为FLOAT(5,1)、DOUBLE(5,1)和DECIMAL(5,1),向表中插入数据5.12、5.15和5.123,SQL语句如下:
CREATE TABLE tmp2 ( x FLOAT(5,1), y DOUBLE(5,1), z DECIMAL(5,1) );
插入数据
INSERT INTO tmp2 VALUES(5.12, 5.15, 5.123);
在插入数据时,给一警告warning
show warning;
可以看到float和double在四舍五入时没有给出警告,而给出z字段数值被截断的警告。
查看结果:
float和double在不指定精度时,默认会按照实际精度(由计算机硬件和操作系统决定),decimal如不指定精度,默认(10,0)。
浮点数相对于定点数的优点是在长度一定的情况下 ,浮点数能够表达更大的数据范围,它的缺点是会引起精度问题。
定点数以字符串的形式存储,在对精度要求比较高的时候(如货币,科学数据等)使用DECIMAL的类型比较好,另外两个浮点数进行减法和比较运算时也容易出现问题,在使用浮点时,尽量避免做浮点数比较
5.1.3日期与时间类型
类型名称 | 日期格式 | 日期范围 | 存储需求 |
---|---|---|---|
YEAR | YYYY | 1901~2155 | 1字节 |
TIME | HH:MM:SS | -838:59:59~838:59:59 | 3字节 |
DATE | YYYY-MM-DD | 1000-01-01~9999-12-31 | 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 | 1970-01-01 00:00:01 UTC~2038-01-19 03:14:07 UTC | 4字节 |
1.YEAR
可以使用各种格式指定YEAR的值。
(1)以4位字符串或者4位数字格式表示的YEAR,范围为“1901”~“2155”。输入的格式为YYYY,‘YYYY’,如输入‘2019’和2019,插入到数据库中均为2019.
(2)以2位字符串格式表示的YEAR,范围为‘00’到’99’。‘00’ 到69’表示 2000-2069 。'70’到’99’表示1970-1999范围的YEAR值。‘0’与‘00’的作用相同,插入超过取值范围的值,将被转换为2000。
(3)以2位数字表示的YEAR,范围为1~99。1到69的范围值转换为2001-2069;70到99的范围值转换为1970-1999的YEAR值。在这里0的值将会转换为0000,而不是2000。只有使用字符串格式的‘0’和‘00’才能正确的解析
例子1四位字符串:创建数据类型为YEAR的字段y,往里插入值,插入一个超过范围的值。
首先创建表tmp3:
CREATE TABLE tmp3( y YEAR );
向表中插入数据:
INSERT INTO tmp3 values(2010),('2010');
再次向表中插入数据:
INSERT INTO tmp3 values ('2166');
插入2166大于范围2155,因此报错
查看结果:没有插入成功
例子2二位字符串:查看‘0’‘00’与0的区别
首先删除表中的数据:
DELETE FROM tmp3;
向表中插入数据:
INSERT INTO tmp3 values('0'),('00'),('77'),('10'),(0),(78),(11);
查看结果:
SELECT * FROM tmp3;
2.TIME
可以使用各种格式指定TIME值:
(1)‘D HH:MM:SS’格式的字符串。还可以使用下面任何一种非严格语法:‘HH:MM:SS’, ‘HH:MM’, ‘D HH:MM’, 'D HH’或’SS‘。这里的D表示日,可以取0~34之间的值。在插入数据库时,D被转换为小时保存,格式为’D*24+HH。
(2)‘HHMMSS’格式的,没有间隔符的字符串或者HHMMSS格式的数值,假定是有意义的时间。如‘101112’被理解为10:11:12,但是‘107212’就是不合法的(72是没有意义的分钟部分),存储时将变成00:00:00。
在简写时间时,如果没有冒号,MySQL从右开始解析,假定最右的两位表示秒。(解释TIME的值为过去时间而不是当前时间)例如:1112和‘1112’并不是表示11:12:00而是解析为00:11:12。相反如果有冒号存在,被看作当天时间11:12和‘11:12’均表示11:12:00。
例子1:查看不同插入格式的TIME值
首先创建表tmp4,
CREATE TABLE tmp4( t TIME );
向表中插入数据:
INSERT INTO tmp4 values('10:05:05 '), ('23:23'), ('2 10:10'), ('3 02'),('10');
查看结果:
SELECT * FROM tmp4;
’2 10:10’被转换为58:10:00((224+10):10:00),’3 02’被转换为74:00:00((324+2):00:00);
在使用’D HH’格式时,小时一定要使用双位数值,如果是小于10的小时数,应在前面加0。
例子2:插入非法数据和当前时间
首先删除表中的数据:
DELETE FROM tmp4;
向表中插入数据:
INSERT INTO tmp4 values (CURRENT_TIME) ,(NOW());
再向表中插入数据:
INSERT INTO tmp4 values ( 107010);
插入CURRENT_TIME ,now()都为当前时间。 插入的107010数值,解析为10:70:10,其中70为无意义的分钟数值,因此插入失败。
3.DATE
再给DATE类型的字段赋值时,可以使用字符串类型或数字类型的数据插入,只要符合DATE的日期格式即可:
(1)以‘YYYY-MM-DD’或者’YYYYMMDD’字符串格式表示的日期,取值范围为‘1000-01-01’~‘9999-12-31’。例如‘20191212’和‘2019-12-12’解析为2019-12-12。
(2)以‘YY-MM-DD’或者’YYMMDD’字符串格式表示的日期以及用YY-MM-DD或者YYMMDD数字格式表示的日期,两位的年值令人感到模糊不知道世纪。为此MySQL使用以下规则解释两位年值:‘00’ 到69’表示 2000-2069 。'70’到’99’表示1970-1999范围的YEAR值。例如:‘981231’表示为1998-12-31;‘12-12-31’表示为2012-12-31。
(3)使用CURRENT_DATE或者now(),插入当前系统日期。
例子1:数字和字符串格式的两位年份。定义数据类型为DATE的字段d,向表中插入“YY-MM-DD” 和 “YYMMDD” 字符串格式日期以及YY-MM-DD和YYMMDD数字格式的日期。
首先创建表tmp5:
CREATE TABLE tmp5(d DATE);
向表中插入“YY-MM-DD”和“YYMMDD”格式日期:
INSERT INTO tmp5 values ('99-09-09'),( '990909'), ('000101') ,('111111');
向表中插入YY-MM-DD和YYMMDD数字格式日期:(这个格式会报错,网上搜索没有解决,但是书上说是可以)
INSERT INTO tmp5 values (99-09-10),(990910), ( 000102) ,( 111112);
查看插入结果:
SELECT * FROM tmp5;
MySQL中允许不严格语法:任何标点符号都可以用作日期部分间的分隔符。如-,., /,@等
4.DATETIME
DATETIME类型用在需要同时包含日期和时间信息的值,在存储时需要8个字节。格式为”YYYY-MM-DD HH:MM:SS“,可以使用字符串类型或者数字类型的数据插入,只要符合格式即可。参考DATE和TIME的相关描述。
插入当前系统时间now()。
例子:创建数据表tmp6,定义数据类型为DATETIME的字段dt,向表中插入“YYYY-MM-DD HH:MM:SS”和“YYYYMMDDHHMMSS”字符串格式日期和时间值
首先创建表tmp6:
CREATE TABLE tmp6( dt DATETIME );
向表中插入“YYYY-MM-DD HH:MM:SS”和“YYYYMMDDHHMMSS”格式日期:
INSERT INTO tmp6 values('1998-08-08 08:08:08'),('19980808080808'),('20101010101010');
查看插入结果:
SELECT * FROM tmp6;
5.TIMESTAMP
TIMESTAMP的显示格式与DATETIME相同,显示宽度固定在19个字符,日期格式为YYYY-MM-DD HH:MM:SS,在存储时需要4个字节。但是TIMESTAMP的取值范围小于DATETIME,为‘1970-01-01 00:00:01’ UTC~‘2038-01-19 03:14:07’ UTC,其中UTC指世界标准时间,因此在插入数据是要注意是否合法。
例子:创建数据表tmp7,定义数据类型为TIMESTAMP的字段ts,向表中插入 值’19950101010101’,’950505050505’,’1996-02-02 02:02:02’,’97@03@03 03@03@03’,121212121212,NOW(),SQL语句如下
CREATE TABLE tmp7( ts TIMESTAMP);
向表中插入数据:
INSERT INTO tmp7 values ('19950101010101'),
('950505050505'),
('1996-02-02 02:02:02'),
('97@03@03 03@03@03'),
(121212121212),
( NOW() );
查看插入结果:
SELECT * FROM tmp7;
由结果可以看到,’19950101010101’被转换为1995-01-01 01:01:01;’950505050505’被转换为1995-05-05 05:05:05;’1996-02-02 02:02:02’被转换为1996-02-02 02:02:02;’97@03@03 03@03@03’被转换为1997-03-03 03:03:03;121212121212被转换为2012-12-12 12:12:12;NOW()被转换为系统当前日期时间2013-03-24 09:17:49。
TIMESTAMP与DATETIME除了存储字节和支持的范围不同外,还有一个最大的区别就是:DATETIME在存储日期数据时,按实际输入的格式存储,即输入什么就存储什么,与时区无关;而TIMESTAMP值的存储是以UTC(世界标准时间)格式保存的,存储时对当前时区进行转换,检索时再转换回当前时区。即查询时,根据当前时区的不同,显示的时间值是不同的
例子:更改时区,再次查看插入值
先查看当前时区
更改时区为东10区。并再次查看插入值。
更改为东10区
set time_zone='+10:00';
东10比东8快2个小时,经过时区转换后,显示值增加了2个小时。
5.1.4文本字符串类型
文本字符串可以进行区分或者不区分大小写的串比较,另外还可以进行模式匹配查找。
类型名称 | 说明 | 存储需求 |
---|---|---|
CHAR(M) | 固定长度非二进制字符串 | M字节,1<=M<=255 |
VARCHAR(M) | 变长非二进制字符串 | L+1字节,在此L<=M和1<=M<=255 |
TINYTEXT | 非常小的非二进制字符串 | L+1字节,在此L<2^8 |
TEXT | 小的非二进制字符串 | L+2字节,在此L<2^16 |
MEDIUMTEXT | 中等大小的非二进制字符串 | L+3字节,在此L<2^24 |
LONGTEXT | 大的非二进制字符串 | L+4字节,在此L<2^32 |
ENUM | 枚举类型,只能有一个枚举字符串值 | 1或2个字节,取决于枚举值的数目(最大值65535) |
SET | 一个设置,字符串对象可以有零个或者多个SET成员 | 1,2,3,4或8个字节,取决于集合成员的数量(最多64个成员) |
VARCHAR和TEXT与BLOB(二进制数据类型)一样是变长类型,对于其存储需求取决于列值的实际长度(L),而不是取决于类型的最大可能尺寸。例如:varchar(10)列能保存最大长度为10个字符的一个字符串,实际存储需要的是字符串的长度L,加上1个字节以记录字符串的长度。对于字符”ABCD“,L是4而要存储的长度是5个字节。
1.CHAR和VARCHAR类型
CHAR(M)为固定长度字符串,在定义时指定字符串列长。当保存在右侧填充空格以达到指定的长度。M表示列长度,M的范围是0~255字符。例如:char(4)定义了一个长度为4的字符串列,其包含的最大字符个数为4。当检索到char时,尾部的空格将被删除。
VARCHAR(M)是长度可变的字符串,M是最大列长度。M的范围是0~65535。VARCHAR的最大实际长度由最长行的大小和使用的字符集确定,而其实际占用的空间为字符串的长度加1。例如:varchar(50)定义了一个最大长度为50的字符串,如果插入的字符串只有10,则实际的存储的字符串为10个字符加上一个字符串结束字符,长度为11。
下面将不同字符串保存到CHAR(4)和VARCHAR(4)中,说明差别。
插入值 | CHAR(4) | 存储需求 | VARCHAR(4) | 存储需求 |
---|---|---|---|---|
‘’ | ‘ ’ | 4字节 | ‘’ | 1字节 |
‘ab’ | ‘ab ’ | 4字节 | ‘ab’ | 3字节 |
‘abc’ | ‘abc’ | 4字节 | ‘abc’ | 4字节 |
‘abcd’ | ‘abcd’ | 4字节 | ‘abcd’ | 5字节 |
‘abcdef’ | ‘abcd’ | 4字节 | ‘abcd’ | 5字节 |
例子:定义字段ch和vch数据类型依次为CHAR(4)、VARCHAR(4)向表中插入数据“ab ”,SQL语句如下:
创建表tmp8:
CREATE TABLE tmp8(
ch CHAR(4), vch VARCHAR(4)
);
输入数据:
INSERT INTO tmp8 VALUES('ab ', 'ab ');
查询结果:
SELECT concat('(', ch, ')'), concat('(',vch,')') FROM tmp8;
char类型在保存空格时被删除了,而varchar保存着空格。
2.TEXT类型
TEXT列保存非二进制字符串,如文章内容,评论等。当保存或查询TEXT列的值的时候,不删除尾部空格。
(1)TINYTEXT的最大长度为255(2^8-1)字符的TEXT列。
(2)TEXT最大长度为65535(2^16-1)字符的TEXT列。
(3)MEDIUMTEXT最大长度为16777215(2^24-1)字符的TEXT列。
(4)LONGTEXT最大长度为4294967295或4GB(2^32-1)字符的TEXT列。
3.ENUM类型
ENUM是一个字符串对象,其值为表创建时在列规定中枚举的一列值。语法如下:
字段名 ENUM(’值1’,‘值2’,...,'值3')
字段名指将要定义的字段,值n指枚举列表中的第n个值。ENUM类型的字段在取值时,只能在指定的枚举列表中取值,而且一次只能取一个。如果创建的成员中有空格,其尾部的空格将自动被删除。ENUM值在内部用整数表示,每个枚举值均有一个索引值:列表值所允许的成员值从1开始编号,MySQL存储的就是这个索引编号,枚举最多有65535个元素。
ENUM的值按照索引顺序排列,并且空字符串排在非空字符串前,NULL值排在其他所有的枚举值前
例子:定义ENUM类型的列enm(‘first’,‘second’,‘third’),查看列成员的索引值,SQL语句如下:
首先,创建tmp9表:
CREATE TABLE tmp9( enm ENUM('first','second','third') );
插入各个列值:
INSERT INTO tmp9 values('first'),('second') ,('third') , (NULL);
查看索引值:
SELECT enm, enm+0 FROM tmp9;
ENUM列总有一个默认值,如果将ENUM列声明为NULL,NULL值为该列的一个有效值,并且默认值为NULL。如果ENUM列被声明为NOT NULL,其默认值为允许的值列表的第一个元素
例子:定义INT类型的soc字段,ENUM类型的字段level,列表值为(‘excellent’,‘good’, ‘bad’),向表tmp10中插入数据’good’,1,2,3,’best’,SQL语句如下:
首先,创建数据表:
CREATE TABLE tmp10 (soc INT, level enum('excellent', 'good','bad') );
插入数据:
INSERT INTO tmp10 values(70,'good'), (90,1),(75,2),(50,3);
再次插入数据:
INSERT INTO tmp10 values (100,'best');
由于字符串”best“不在列表ENUM中,所以对数据进行了阻止插入的操作。查询结果如下:
由结果可以看到,因为ENUM列表中的值在MySQL中都是以编号序列存储的,因此,插入列表中的值“good”或者插入其对应序号’2’的结果是相同的;“best”不是列表中的值,因此不能插入数据。
4.SET类型
SET是一个字符串对象,可以有零或多个值,SET列最多有64个成员,其值为表创建时规定的一列值。指定包括多个SET成员的SET列值时,各成员之间用逗号隔开。语法如下:
SET(’值1’,‘值2’,...,'值3')
与ENUM不同的是,ENUM类型的字段只能从定义的列值中选择一个值插入 ,而SET类型的列可从定义的列值中选择多个字符的联合。
如果插入SET字段中列值有重复,则MySQL自动删除重复的值;插入SET字段的值的顺序并不重要,MySQL会在存入数据时,按照定义的顺序显示;如果插入了不正确的值,默认情况下,MySQL会忽视这些值,并给出警告。
例子:定义SET类型的字段s,取值列表为(‘a’, ‘b’, ‘c’, ‘d’),插入数据(‘a’),(‘a,b,a’),(‘c,a,d’),(‘a,x,b,y’),SQL语句如下:
首先创建表tmp11:
CREATE TABLE tmp11 ( s SET('a', 'b', 'c', 'd'));
插入数据:
INSERT INTO tmp11 values('a'),( 'a,b,a'),('c,a,d');
再次插入数据:
INSERT INTO tmp11 values ('a,x,b,y');
因为插入了不再set列不支持的值,给错误提示。查看结果:
从结果可以看到,对于SET来说如果插入的值为重复的,则只取一个,例如“a,b,a”,则结果为“a,b”;如果插入了不按顺序排列值,则自动按顺序插入,例如“c,a,d”,结果为“a,c,d”;如果插入了不正确值,该值将被阻止插入,例如插入值“a,x,b,y”。
5.15二进制字符串类型
类型名称 | 说明 | 存储需求 |
---|---|---|
BIT(M) | 位字段类型 | 大约(M+7)/8个字节 |
BINARY(M) | 固定长度二进制字符串 | M个字节 |
VARBINARY(M) | 固定长度二进制字符串 | M+1个字节 |
TINYBLOB(M) | 非常小的BLOB | L+1字节,在此L<2^8 |
BLOB(M) | 小BLOB | L+2字节,在此L<2^16 |
MEDIUMBLOB (M) | 中等大小的BLOB | L+3字节,在此L<2^24 |
LONGBLOB(M) | 非常大的BLOB | L+4字节,在此L<2^32 |
1.BIT类型
BIT类型是位字段类型。M表示每个值的位数,范围为1~64。如果M被省略,默认为1.如果BIT(M)列分配的值的长度小于M位,在值的左边用0填充。例如,为BIT(6)列分配b’101’,其效果与b’000101’相同。BIT数据类型用来保存位字段值,例如以二进制的形式保存数据13,其二进制形式为1101,需要定义类型BIT(4)。
例子:定义BIT(4)类型的字段b,向表中插入数据2、9、15、16。SQL语句如下:
CREATE TABLE tmp12( b BIT(4) );
插入数据:
INSERT INTO tmp12 VALUES(2), (9), (15);
查询插入结果:
SELECT BIN(b+0) FROM tmp12;
其中BIN()是将数字转换为二进制,b+0是将二进制的结果转换为对应的数字的值。
MySQL中不允许插入超出该列允许范围的值
2.BINARY 和VARBINARY类型
BINARY 和VARBINARY类似与CHAR 和VARCHAR,不同的是它们包含二进制字符串。
列名称 BINARY(M)或 VARBINARY(M)
BINARY(M)的长度是固定的,指定长度后,不足最大长度的,将在它们右边填充‘\0’以补齐到达指定长度。例如:当指定列长度为BINARY(3)时,当插入’a’时,存储的实际是‘a\0\0’,当插入”ab“时,实际存储为’ab\0’,不论存储的内容是否达到指定的长度,其存储空间均为M。
VARBINARY(M)的长度是可变的。指定好长度之后,其值在0和最大值之间。例如,VARBINARY(20),如果插入的值的长度只有10,则实际存储为10+1,其实际占用空间为字符串的实际长度加一。
例子:定义BINARY(3)类型的字段b和VARBINARY(3)类型的字段vb,并向表中插入数据’5’,比较两个字段的存储空间。
CREATE TABLE tmp13(
b binary(3), vb varbinary(30)
);
插入数据:
INSERT INTO tmp13 VALUES(5,5);
查看两个字段存储数据的长度:
SELECT length(b), length(vb) FROM tmp13;
如果想要进一步确认’5’在两个字段中不同的存储方式,输入如下语句:
SELECT b,vb,b = '5', b='5\0\0',vb='5',vb = '5\0\0' FROM tmp13;
从查询长度可以看到,b字段的值数据长度为3,而vb字段的数据长度仅为插入的一个字符的长度1。由查询值的结果可以看出,b字段和vb字段的长度是截然不同的,因为b字段不足的空间填充了’\0’,而vb字段则没有填充。
3.BLOB类型
BLOB是一个二进制大对象,用来存储可变数量的数据。
数据类型 | 存储范围 |
---|---|
TINYBLOB | 最大长度为255(2^8-1)B |
BLOB | 最大长度为65535(2^16-1)B |
MEDIUMBLOB | 最大长度为16777215(2^24-1)B |
LONGBLOB | 最大长度为4294967295B或4GB(2^32-1)B |
BLOB列没有字符集,并且排序和比较基于列值字节的数值;TEXT列有一个字符集,并且根据字符集进行排序和比较。