第 5 章数据类型与表的约束 学习目标: .掌握MySQL中的各种数据类型; .掌握MySQL中表的各种约束。 在数据库中,数据表用来组织和保存数据,它由表结构和表中数据构成。 在设计表结构时,经常需要根据实际需求,选择合适的数据类型和约束。本 章介绍数据类型和表中的各种约束。 5.数据类型 1 使用MySQL数据库存储数据时,不同的数据类型决定了MySQL存储 数据方式的不同。MySQL数据库提供了多种数据类型,本节对这些数据类 型进行讲解。 5.1.1 数字类型 在数据表中,经常需要存储一些数字,如学生的年龄、商品的价格等,这 需要数字类型进行存储。数字类型包括整数类型、浮点数类型、定点数类型、 bit(位)类型等。 1.整数类型 MySQL提供的整数类型包括tinyint、smalint、mediumint、int和 bigint。整数类型的属性字段可以添加auto_increment自增约束条件。不同 整数类型所对应的字节大小和取值范围不同,如表5-1所示。 表5- 1 整数类型 g 数据类型字节数无符号取值范围有符号取值范围 tinyint 1 0~281 -27~271 smalint 2 0~2161 -215~2151 mediumint 3 0~2241 -223~2231 int 4 0~2321 -231~2311 biint 8 0~2641 -263~2631 68 MySQL 8.0 数据库原理与应用 从表5-1中可以看出,不同整数类型所占用的字节数和取值范围都是不同的。其中,占 用字节数最小的是tinyint,占用字节数最大的是bigint。不同整数类型的取值范围可以根 据字节数计算出来,如tinyint类型的整数占用1字节,1字节是8位,那么tinyint类型无符 号数的最大值就是28-1(即255),有符号数的最大值就27-1(即127)。同理,可以算出其 他不同整数类型的取值范围。 需要注意的是,若使用无符号数据类型,需要在数据类型右边加上unsigned关键字来 修饰,如intunsigned表示无符号int类型。 下面通过案例来演示整数类型的使用。 【例5-1】 创建名称为int_test的数据表,字段类型用int和intunsigned来定义。具 体SQL语句与执行结果如下。 mysql> create table int_test( -> i1 int, -> i2 int unsigned -> ); Query OK, 0 rows affected (0.63 sec) 在数据表int_test中,i1是有符号类型,i2是无符号类型。 【例5-2】 插入整型数据。当数据在合法范围内,可以插入,反之提示错误信息。具体 SQL语句与执行结果如下。 mysql> insert into int_test values(500,500); Query OK, 1 row affected (0.20 sec) mysql> insert into int_test values(-500,-500); ERROR 1264 (22003): Out of range value for column 'i2' at row 1 从以上执行结果可以看出,-500超出了无符号int类型i2的取值范围,插入失败, MySQL显示了错误信息。 2.浮点数类型 在MySQL中,存储的小数都是使用浮点数或定点数来表示的。浮点数的类型有两种, 分别是单精度浮点数(float)和双精度浮点数(double),对应的字节大小及其取值范围如 表5-2所示。 表5-2 浮点数类型 数据类型字 节 数负数取值范围非负数取值范围 float 4 -3.402823466E+38~ -1.175494351E-38 0和1.175494351E-38~ 3.402823466E+38 double 8 -1.7976931348623157E+308~ -2.2250738585072014E-308 0和2.2250738585072014E-308~ 1.7976931348623157E+308 表5-2中列举的取值范围是理论上的极限值,但根据不同的硬件或操作系统,实际范围 可能会小。另外,当浮点数类型使用unsigned修饰为无符号时,取值范围将不包含负数。 第5 章 数据类型与表的约束 69 浮点数类型虽然取值范围很大,但是精度并不高。float的精度大约是6位,double的 精度大约是15位。如果超出精度,可能会导致给定的数值与实际保存的数值不一致,发生 精度损失。 为了更好地理解,下面通过案例演示浮点数类型的使用。 【例5-3】 创建名称为float_test的数据表,具体SQL语句与执行结果如下。 mysql> create table float_test( -> f1 float, -> f2 float); Query OK, 0 rows affected (0.27 sec) 数据表创建成功。 【例5-4】 插入float类型的数据,具体SQL语句与执行结果如下。 mysql> insert into float_test values(1234567,1.234567); Query OK, 1 row affected (0.04 sec) 数据插入成功后,可以使用select语句查询表中的数据,执行结果如下。 mysql> select * from float_test; +---------+---------+ | f1 | f2 | +---------+---------+ | 1234570 | 1.23457 | +---------+---------+ 1 row in set (0.00 sec) 从以上结果中可以看出,当一个数字的整数部分和小数部分加起来达到7位时,第7位 就会被四舍五入。 3.定点数类型 定点数类型(decimal)通过decimal(M,D)设置位数和精度,其中M 表示数值总位数 (不包括“.”和“-”),最大值为65,默认值为10;D表示小数点后的位数,最大值为30,默认 值为0。例如,decimal(6,3)表示的取值范围是-999.999~999.999。系统会自动根据存储 的数据来分配存储空间。如果不允许保存负数,可以通过unsigned修饰。 为了更好地理解,下面通过案例演示定点数类型的使用。 【例5-5】 创建名称为decimal_test的数据表,具体SQL语句与执行结果如下。 mysql> create table decimal_test( -> d1 decimal(5,2), -> d2 decimal(5,2)); Query OK, 0 rows affected (0.60 sec) 数据表创建成功。 70 MySQL 8.0 数据库原理与应用 【例5-6】 插入一条数据(123.124,123.125),具体SQL语句与执行结果如下。 mysql> insert into decimal_test values(123.124,123.125); Query OK, 1 row affected, 2 warnings (0.05 sec) 数据插入成功后,出现了两条警告信息,查看警告信息,结果如下。 mysql> show warnings; +-------+------+-----------------------------------------+ | Level | Code | Message | +-------+------+-----------------------------------------+ | Note | 1265 | Data truncated for column 'd1' at row 1 | | Note | 1265 | Data truncated for column 'd2' at row 1 | +-------+------+-----------------------------------------+ 2 rows in set (0.04 sec) 警告信息显示出现了数据截断,可以使用select语句查询表中数据,执行结果如下。 mysql> select * from decimal_test; +--------+--------+ | d1 | d2 | +--------+--------+ | 123.12 | 123.13 | +--------+--------+ 1 row in set (0.00 sec) 从以上执行结果可以看出,小数部分被四舍五入。 【例5-7】 插入一条数据(999.99,999.999),具体SQL语句与执行结果如下。 mysql> insert into decimal_test values(999.99,999.999); ERROR 1264 (22003): out of range value for column 'd2' at row 1 从以上执行结果可以看到,数据插入失败。 从例5-6和例5-7可以看出,若小数部分超出范围,会进行四舍五入,并出现数据截断 (datatruncated)警告;若整数部分超出范围,数据会插入失败,提示超出取值范围(outof rangevalue)错误。 注意:浮点数类型也可以设置位数和精度,但仍有可能损失精度,在实际使用过程中应 避免使用浮点数类型,以免出现不能人为控制的问题。因此,对于小数类型的数据,建议使 用定点数类型。 4.bit(位)类型 bit(位)类型用于存储二进制数据,语法为bit(M),M 表示位数,范围为1~64。 为了更好地理解,下面通过案例演示bit类型的使用。 【例5-8】 以保存字符A 为例,A 的ASCII码对应十进制65,对应二进制1000001,总 共有7位,因此需要bit(7)保存。具体SQL语句与执行结果如下。 第5 章 数据类型与表的约束 71 mysql> select ASCII('A'); +------------+ | ASCII('A') | +------------+ | 65 | +------------+ 1 row in set (0.05 sec) 获取字符A 的ASCII码,结果是65。 mysql> select bin(65),length(bin(65)); +---------+-----------------+ | bin(65) | length(bin(65)) | +---------+-----------------+ | 1000001 | 7 | +---------+-----------------+ 1 row in set (0.10 sec) 获取字符A 的二进制数,并计算长度,结果为1000001和7。 mysql> create table bit_test(b bit(7)); Query OK, 0 rows affected (0.25 sec) 数据表创建成功。 mysql> insert into bit_test values(65); Query OK, 1 row affected (0.59 sec) 插入数据成功。 mysql> select bin(b) from bit_test; +---------+ | bin(b) | +---------+ | 1000001 | +---------+ 1 row in set (0.00 sec) 查询数据并转换为二进制数显示,结果为1000001。 从以上执行结果可以看出,利用MySQL中的ASCII()、bin()、length()函数可以方便 地查询ASCII码、二进制值和数字长度。bit类型字段在数字插入时转换为二进制保存,但 在利用select查询时,可以转换为对应的字符显示。 5.1.2 时间和日期类型 在处理日期和时间类型的值时,MySQL有不同的数据类型供用户选择。它们可以被 72 MySQL 8.0 数据库原理与应用 分为简单的日期和时间类型、混合的日期和时间类型。根据要求的精度,子类型在每个分类 型中都可以使用,并且MySQL带有内置功能,可以将多样化的输入格式变为一个标准格 式。日期和时间类型同样有对应的字节数和取值范围,如表5-3所示。 表5-3 日期和时间类型 数据类型字节数取值范围日期格式零 值 year 1 1901~2155 YYYY 0000 date 4 1000-01-01~9999-12-31 YYYY-MM-DD 0000-00-00 time 3 -838:59:59~838:59:59 HH:MM:SS 00:00:00 datetime 8 1000-01-0100:00:00~ 9999-12-3123:59:59 YYYY-MM-DD HH:MM:SS 0000-00-00 00:00:00 timestamp 4 1970-01-0100:00:01~ 2038-01-1903:14:07 YYYY-MM-DD HH:MM:SS 0000-00-00 00:00:00 在表5-3中,日期格式YYYY表示年,MM 表示月,DD表示日。每种日期和时间类型 的取值范围都是不同的。需要注意的是,如果插入的数值不合法,系统会自动将对应的零值 插入数据表中。 下面详细讲解日期和时间类型。 1.year类型 year类型用于年份。 【例5-9】 创建名称为year_test的数据表,并插入数据。具体SQL语句与执行结果如下。 mysql> create table year_test(y year); Query OK, 0 rows affected (0.17 sec) mysql> insert into year_test values(2022); Query OK, 1 row affected (0.14 sec) 在MySQL中,可以使用以下3种格式指定year类型的值。 (1)使用4位字符串或数字表示,为'1901'~'2155'或1901~2155。例如输入'2022'或 2022,插入数据库中的值均为2022。 (2)使用两位字符串表示,为0' 0'~9' 9',其中,0' 0'~6' 9'的值会被转换为2000~2069的 year值,7' 0'~9' 9'的值会被转换为1970~1999的year值。例如输入2' 2',插入数据表中的值 为2022。 (3)使用两位数字表示,为1~99,其中,1~69的值会被转换为2001~2069的year值, 70~99的值会被转换为1970~1999的year值。例如输入22,插入数据表中的值为2022。 需要注意的是,当使用year类型时,一定要区分0' '和0。因为字符串格式0' '表示的year 值是2000,而数字格式的0表示的year值是0000。 2.date类型 date类型用于表示日期值,不包含时间部分。 【例5-10】 创建名称为date_test的数据表,并插入数据。具体SQL语句与执行结果 如下。 第5 章 数据类型与表的约束 73 mysql> create table date_test(d date); Query OK, 0 rows affected (0.19 sec) mysql> insert into date_test values('2022-04-03'); Query OK, 1 row affected (0.15 sec) 在MySQL 中,可以使用以下4种格式指定date类型的值。 (1)以'YYYY-MM-DD'或者'YYYYMMDD'字符串格式表示。例如,输入2' 022-04-03'或 2' 0220403',插入数据库中的日期都为2022-04-03。 (2)以'YY-MM-DD'或者'YYMMDD'字符串格式表示。YY 表示的是年,为'00'~ '99', 其中,0' 0'~6' 9'的值会被转换为2000~2069的year值,7' 0'~9' 9'的值会被转换为1970~ 1999的year值。例如输入2' 2-04-03'或2' 20403',插入数据库中的日期都为2022-04-03。 (3)以YY-MM-DD或者YYMMDD数字格式表示。例如输入22-04-03或220403,插 入数据库中的日期都为2022-04-03。 (4)使用current_date输入当前系统日期。 3.time类型 time类型用于表示时间值,它的显示形式一般为HH:MM:SS,其中HH 表示小时, MM 表示分,SS表示秒。在MySQL中,可以使用以下3种格式指定time类型的值。 (1)以'HHMMSS'字符串或者HHMMSS数字格式表示。例如输入1' 21212'或121212, 插入数据库中的时间为12:12:12。 (2)以'D HH:MM:SS'字符串格式表示。其中,D表示日,可以取0~34的值,插入数 据时,小时的值等于(D×24+HH)。例如,输入'211:30:50',插入数据库中的时间为59: 30:50;输入1' 1:30:50',插入数据库中的时间为1' 1:30:50';输入3' 022:59:59',插入数据库 中的时间为742:59:59。 (3)使用current_time输入当前系统时间。 4.datetime类型 datetime类型用于表示日期和时间,它的显示形式为'YYYY-MM-DD HH:MM:SS', 其中YYYY表示年,MM 表示月,DD 表示日,HH 表示小时,MM 表示分,SS表示秒。在 MySQL中可以使用以下4种格式指定datetime类型的值。 (1)以'YYYY-MM-DD HH:MM:SS'或者'YYYYMMDDHHMMSS'字符串格式表示 的日期和时间,取值范围为1' 000-01-0100:00:00'~9' 999-12-3123:59:59'。例如,输入2' 014- 01-2209:01:23'或'20140122090123',插入数据库中的datetime值都为2014-01-2209: 01:23。 (2)以'YY-MM-DD HH:MM:SS'或者'YYMMDDHHMMSS'字符串格式表示的日期 和时间,其中YY表示年,取值范围为0' 0'~ 9' 9',与date类型中的YY相同,0' 0'~6' 9'的值会 被转换为2000~2069的year值,7' 0'~9' 9'的值会被转换为1970~1999的year值。 (3)以YYYYMMDDHHMMSS或者YYMMDDHHMMSS数字格式表示的日期和 时间。例如,插入20140122090123或者140122090123,插入数据库中的datetime值都为 2014-01-2209:01:23。 (4)使用now()来输入当前系统的日期和时间。 74 MySQL 8.0 数据库原理与应用 5.timestamp类型 timestamp(时间戳)类型用于表示日期和时间,它的显示形式与datetime相同,但取值 范围比datetime小,下面介绍几种timestamp类型与datetime类型不同的形式,具体如下。 (1)使用current_timestamp来输入系统当前日期和时间。 (2)无任何输入,或输入null时,实际保存的是系统当前日期和时间。 注意:在MySQL 中,timestamp字段默认情况下会自动设置notnulldefaultcurrent_ timestamponupdatecurrenttimestamp属性,具体解释如下。 (1)notnull表示非空约束,该字段将不允许保存null值。 (2)default表示默认约束,当字段无任何输入时,自动设置某个值作为默认值。此处设 为current_timestamp表示使用系统当前日期和时间作为默认值。 (3)onupdate用于当一条记录中的其他字段被update语句修改时,自动更改该字段为 某个值。此处设为current_timestamp表示每次修改时保存修改时的系统日期和时间。 若为timestamp字段手动设置default属性时,该字段将不会自动设置onupdate属性。 5.1.3 字符串类型 字符串类型用来存储字符串数据,除了可以存储字符串数据之外,还可以存储其他数 据,如图片和声音的二进制数据。MySQL支持两类字符型数据:文本字符串和二进制字符 串。文本字符串类型包括char、varchar、text、enum 和set,二进制字符串类型包括binary、 varbinary和blob。 1.char和varchar类型 char和varchar类型的语法格式如下。 char(M) 或 varchar(M) char(M)为固定长度字符串,在定义时指定字符串列长。不足指定长度时,在右侧填充 空格,以达到指定的长度。M 表示列长度,M 的范围是0~255个字符。例如char(4)定义 了一个固定长度的字符串列,其包含的字符个数最大是4。当检索到char值时,尾部的空格 将被删除。 varchar(M)是长度可变的字符串,M 表示最大列长度。M 的范围是0~65535。 varchar的最大实际长度由最长的行的大小和使用的字符集确定,而其实际占用的空间为字 符串的实际长度加1。例如,varchar(50)定义了一个最大长度为50的字符串,如果插入的 字符串只有10个字符,则实际存储的字符串为10个字符和一个字符串结束字符。varchar 在保存和检索值时尾部的空格仍保留。 为了对比char和varchar之间的区别,下面以char(4)和varchar(4)为例进行说明,如 表5-4所示。 第5 章 数据类型与表的约束 75 表5-4 char(4)和varchar(4)的对比 插 入 值char(4)存储需求varchar(4)存储需求 ' ' 4字节1字节 a' b' 4字节3字节 a' bc' 4字节4字节 a' bcd' 4字节5字节 从对比结果可以看出,char(4)定义了固定长度为4的列,不管存储的数据长度为多少, 所占用的空间均为4字节;varchar(4)定义的列所占的字节数为实际长度加1。 2.text类型 text类型保存大文本数据,如文章内容、评论等。当保存或查询text列的值时,不删除 尾部空格。text类型分为4种,不同的text类型的存储范围和数据长度不同,如表5-5 所示。 表5-5 text类型 数据类型存储范围数据类型存储范围 tinytext 0~28-1字节mediumtext 0~224-1字节 text 0~216-1字节longtext 0~232-1字节 text类型所保存的最大字符数量取决于字符串实际占用的字节数。 注意:在使用“=”等运算符对char、varchar、text进行比较时,字符串末尾的空格会被 忽略。例如,使用where查询a' '字符串,查询结果中可能包含a后面有空格的情况,反之,如 查询条件字符串末尾有空格,如a' ',空格也会被忽略。 由于数据库对大小写不敏感,因此,char、varchar、text、enum、set类型都不区分大小 写。例如,使用where查询a' '字符串,则'A'和a' '都会被查询出来。而binary、varbinary、blob 类型区分大小写,这是因为它们使用二进制方式保存数据。 3.enum 类型 enum 类型又称为枚举类型,定义enum 类型的语法格式如下。 enum('值1','值2','值3',…, '值n') 在上述格式中,('值1','值2','值3',…,'值n')称为枚举列表,enum 类型的数据只能从枚 举列表中获取,并且只能取一个。 【例5-11】 创建名称为enum_test的数据表,并插入数据。具体SQL语句与执行结果 如下。 mysql> create table enum_test(sex enum('male','female')); Query OK, 0 rows affected (0.36 sec) 数据表创建成功,插入两条数据并查看。 76 MySQL 8.0 数据库原理与应用 mysql> insert into enum_test values('male'),('female'); Query OK, 2 rows affected (0.10 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from enum_test; +--------+ | sex | +--------+ | male | | female | +--------+ 2 rows in set (0.04 sec) 插入枚举列表中没有的数据,从执行结果中可以看出,插入失败。 mysql> insert into enum_test values('ma'); ERROR 1265 (01000): Data truncated for column 'sex' at row 1 enum 值在内部用整数表示,并且每个枚举值均有一个索引值:列表值所允许的成员值 从1开始编号,MySQL存储的就是这个索引编号。枚举最多可以有65535个元素。 4.set类型 set类型用于保存字符串对象,其定义格式与enum 类型相似,语法格式如下。 set('值1','值2','值3',…, '值n'); set类型的列表中最多可以有64个值,且列表中的每个值都有一个顺序编号,为了节省 空间,实际保存在记录中的也是顺序编号,但在select、insert等语句进行操作时,仍然要使 用列表中的值。 set类型与enum 类型的区别在于,可以从列表中选择一个或多个值来保存,多个值之 间用逗号分隔。 【例5-12】 创建名称为set_test的数据表,并插入数据。具体SQL语句与执行结果 如下。 mysql> create table set_test(t set('book','game','code')); Query OK, 0 rows affected (0.15 sec) 数据表创建成功,插入3条数据并查看。 mysql> insert into set_test values(''),('book'),('book,game'); Query OK, 3 rows affected (0.04 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from set_test; +-----------+ | t |