数据库表由多列字段构成,每一个字段指定了不同的数据类型。指定字段得数据类型之后,也就决定了向字段插入的数据内容,例如,当要插入数值的时候,可以将他们存储为整数类型,也可以将它们存储为字符串类型;不同的数据类型也决定了mysql在存储它们的时候使用的方式,以及在使用它们的时候选择什么运算符号进行运算。
1、MySQL数据类型介绍
MySQL支持多种数据类型,主要有数值类型、日期/时间类型和字符串类型。
(1)数值数据类型:包括整数类型TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT和浮点小数据类型FLOAT和DOUBLE、定点小数类型DECIMAL。
(2)日期/时间类型:包括YEAR、TIME、DATE、DATETIME和TIMESTAMP。
(3)字符串类型:包括CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET等。
1.1、整数类型
数值型数据类型主要用来存储数字,MySQL提供了多种数值数据类型。不同的数据类型提供不同的取值范围,可以存储的值范围越大,其所需要的存储空间也就越大。MySQL主要提供的整数类型有:TINYINT、SMALLINT、MEDIUMINT、INT(INTEGER)、BIGINT。整数类型的属性字段可以添加AUTO_INCREMENT自增约束条件。
从表中可以看到,不同类型整数存储所需的字节数是不同的,暂用字节数最小的是TINYINT类型,占用字节最大的是BIGINT类型,相应的占用字节越多的类型所能表示的数值范围越大。
根据占用字节数可以求出每一种数据类型的取值范围,例如TINYINT需要1个字节(8 bits)来存储,那么TINYINT无符号数的最大值为2^8-1,即255;TINYINT有符号数的最大值为2^7-1,即127。其他类型的整数的取值范围计算方法相同。如下图所示:
# 例如: [hellodb]> CREATE TABLE text1 (A TINYINT,B SMALLINT,C MEDIUMINT,D INT,E BIGINT); Query OK, 0 rows affected (0.42 sec) [hellodb]> DESC text1 ; +-------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+-------+ | A | tinyint(4) | YES | | NULL | | | B | smallint(6) | YES | | NULL | | | C | mediumint(9) | YES | | NULL | | | D | int(11) | YES | | NULL | | | E | bigint(20) | YES | | NULL | | +-------+--------------+------+-----+---------+-------+ 5 rows in set (0.00 sec)
可以看到,系统将添加不同默认显示宽度。这些显示宽度能够保证显示每一种数据类型可以取到取值范围内的所有值。例如TINYINT有符号数和无符号的数的取值范围分别为-128-127和0-255,由于负号占了一个数字位,因此TINYINT默认的显示宽度为4,同理,其他整数类型的默认显示宽度与其有符号数的最小值的宽度相同。
注意:显示宽度只用于显示,并不能限制取值范围和占用空间。如:INT(3)会占用4个字节的存储空间,并且允许的最大值也不会是999,而是INT整型所允许的最大值。
不同的整数类型有不同的取值范围,并且需要不同的存储空间,因此,应该根据实际需要选择最
合适的类型,这样有利于提高查询的效率和节省存储空间。整数类型是不带小数部分的数值,现实生活中很多地方都需要用到带小数的数值。
1.2、浮点数类型和定点数类型
MySQL中使用浮点数和定点数来表示小数。浮点类型有两种:单精度浮点类型(FLOAT)和双精度浮点类型(DOUBLE)。定点类型只有一种:DECIMAL。浮点类型和定点类型都可用(M,N)来表示,几种M称为精度,表示总共的位数:N称为标度,是表示小数的位数。具体参照下图:
DECIMAL类型不同于FLOAT和DOUBLE,DECIMAL实际是以串存放的,DECIMAL可能的最大取值范围与DOUBLE一样,但是其有效的取值范围有M和D的值决定。如果改变M而固定D,则其取值范围将随M的变大而变大,从上面图形可以看出,DECIMAL的存储空间并不是固定的,而由其精度值M决定,占用M+2个字节。
注意:不论是定点还是浮点类型,如果用户指定的精度超出精度范围,则会四舍五入进行处理。
# 例如: [hellodb]> CREATE TABLE text2 (A FLOAT(4,1),B DOUBLE(5,1),C DECIMAL(5,1)); Query OK, 0 rows affected (0.43 sec) MariaDB [hellodb]> DESC text2; +-------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+-------+ | A | float(4,1) | YES | | NULL | | | B | double(5,1) | YES | | NULL | | | C | decimal(5,1) | YES | | NULL | | +-------+--------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) [hellodb]> INSERT INTO text2 VALUES(5.12,5.15,5.123); Query OK, 1 row affected, 1 warning (0.06 sec) #有一个警告信息 [hellodb]> SHOW WARNINGS; #查看警告信息 +-------+------+----------------------------------------+ | Level | Code | Message | +-------+------+----------------------------------------+ | Note | 1265 | Data truncated for column ‘C‘ at row 1 | +-------+------+----------------------------------------+ 1 row in set (0.00 sec) #可以看到FLOAT和DOUBLE在进行四舍五入时没有给出警告,而给出C字段数值被截断的警告; [hellodb]> SELECT * FROM text2; #查看表信息 +------+------+------+ | A | B | C | +------+------+------+ | 5.1 | 5.2 | 5.1 | +------+------+------+ 1 row in set (0.01 sec)
# FLOAT和DOUBLE在不指定精度时,默认会按照实际的精度,DECIMAL如不指定精度默认为(10,0)。
浮点数相对于定点数的有点是在长度一定的情况下,浮点数能够表示更大的数据范围:它的缺点是会引起精度问题。
在Mysql中,定点数以字符串形式存储,在对精度要求比较高的时候(如货币,科学数据等)使用DECIMAL的类型比较好,另外两个浮点数进行减法和比较运算时也容易出问题,所以在使用浮点型时需要注意,并尽量避免做浮点数比较。
1.3、日期时间类型
MySQL中有多种表示日期的数据类型,主要有:DATETIME、DATE、TIMESTAMP、TIME和YEAR。例如,当只记录年信息的时候,可以只使用YEAR类型,而没有必要使用DATE。每一种类型都有一个合法的取值范围,当指定确实不合法的值时系统将“零”值插入到数据库中。日期与时间数据类型如下:
#例如: 1、YEAR [hellodb]> CREATE TABLE text3(y YEAR); #创建表text3 Query OK, 0 rows affected (0.40 sec) [hellodb]> INSERT INTO text3 VALUES(2010),(‘2010‘),(‘2166‘); Query OK, 3 rows affected, 1 warning (0.22 sec) Records: 3 Duplicates: 0 Warnings: 1 #插入数据,MySQL给出了一条警告,用SHOW WARNINGS查看警告信息 [hellodb]> SHOW WARNINGS; +---------+------+--------------------------------------------+ | Level | Code | Message | +---------+------+--------------------------------------------+ | Warning | 1264 | Out of range value for column ‘y‘ at row 3 | +---------+------+--------------------------------------------+ 1 row in set (0.00 sec) #可以看到2166超过了YEAR类型的取值范围,但是插入进去了 [hellodb]> SELECT * FROM text3; +------+ | y | +------+ | 2010 | | 2010 | | 0000 | #插入值超过取值范围,所以改为0000 +------+ 3 rows in set (0.00 sec) [hellodb]> DELETE FROM text3; Query OK, 3 rows affected (0.03 sec) #清空表内容 [hellodb]> INSERT INTO text3 VALUES(‘O‘),(‘00‘),(‘77‘),(‘10‘); Query OK, 4 rows affected, 1 warning (0.03 sec) Records: 4 Duplicates: 0 Warnings: 1 #插入两位字符串测试 [hellodb]> SELECT * FROM text3; +------+ | y | +------+ | 0000 | | 2000 | | 1977 | | 2010 | +------+ 4 rows in set (0.01 sec) 2、TIME [hellodb]> CREATE TABLE text4(t TIME); Query OK, 0 rows affected (0.19 sec) [hellodb]> INSERT INTO text4 VALUES (‘10:05:05‘),(‘23:23‘),(‘2 10:10‘),(‘3 02‘),(‘10‘); Query OK, 5 rows affected (0.01 sec) Records: 5 Duplicates: 0 Warnings: 0 [hellodb]> SELECT * FROM text4; +----------+ | t | +----------+ | 10:05:05 | | 23:23:00 | | 58:10:00 | | 74:00:00 | | 00:00:01 | +----------+ 5 rows in set (0.00 sec) #注:在使用‘D HH‘格式时,小时一定要使用双位数值,如果是小于10的小时数,应在其前面加0。 [hellodb]> DELETE FROM text4; #清空表内容 Query OK, 5 rows affected (0.02 sec) [hellodb]> INSERT INTO text4 VALUES(CURRENT_TIME),(NOW()); Query OK, 2 rows affected, 1 warning (0.02 sec) Records: 2 Duplicates: 0 Warnings: 1 #插入当前时间 [hellodb]> SELECT * FROM text4; +----------+ | t | +----------+ | 17:41:29 | | 17:41:29 | +----------+ 2 rows in set (0.00 sec) #注:超出TIME范围但合法的值会被转换为范围最接近的端点,无效的会转换成“00:00:00"。 3、DATE [hellodb]> CREATE TABLE text5(d DATE); Query OK, 0 rows affected (0.40 sec) [hellodb]> INSERT INTO text5 VALUES(‘1998-09-09‘),(‘19980909‘),(‘20101010‘); Query OK, 3 rows affected (0.03 sec) Records: 3 Duplicates: 0 Warnings: 0 [hellodb]> SELECT * FROM text5; +------------+ | d | +------------+ | 1998-09-09 | | 1998-09-09 | | 2010-10-10 | +------------+ 3 rows in set (0.00 sec) #不同类型的日期值都正确的都可以插入到表中 [hellodb]> DELETE FROM text5; Query OK, 3 rows affected (0.02 sec) [hellodb]> INSERT INTO text5 VALUES(CURRENT_DATE()),(NOW()); Query OK, 2 rows affected, 1 warning (0.02 sec) Records: 2 Duplicates: 0 Warnings: 1 #插入当前日期 #CURRENT_DATE只返回当前日期值,不包括时间部分。 #NOW()函数返回日期和时间值,在保存到数据库时,只保留了其日期部分。 [hellodb]> SELECT * FROM text5; +------------+ | d | +------------+ | 2016-03-07 | | 2016-03-07 | +------------+ 2 rows in set (0.01 sec)