MySQL

参考:http://c.biancheng.net/view/2361.html

文章目录

    • 1. 操作数据库
      • 1.1 创建数据库
      • 1.2 查看数据库
      • 1.3 修改数据库
      • 1.4 删除数据库
      • 1.5 使用数据库
    • 2. MySQL 存储引擎
      • 2.1 什么是存储引擎
      • 2.2 MySQL 5.7 支持的存储引擎
      • 2.3 如何选择 MySQL 存储引擎
    • 3. MySQL 常见数据类型
      • 3.1 整数类型
      • 3.2 小数类型
      • 3.3 日期/时间类型
      • 3.4 字符串类型
    • 4. 数据库的字段属性
    • 5.操作数据库表
      • 5.1 创建数据库表
      • 5.2 修改数据表
      • 5.3 删除数据表
    • 6. MySQL 数据管理
      • 6.1 MySQL 主键
      • 6.2 MySQL 外键约束
      • 6.3 MySQL 唯一约束
      • 6.4 MySQL 检查约束
      • 6.5 MySQL 默认值
      • 6.6 MySQL 非空约束
      • 6.7 MySQL 查看表中的约束
      • 6.8 MySQL 查询数据表
      • 6.9 MySQL 去重
      • 6.10 MySQL 设置别名
      • 6.11 MySQL 限制查询结果的记录条数
      • 6.12 MySQL 对查询结果进行排序
      • 6.13 MySQL 条件查询
      • 6.14 MySQL 常用运算符
      • 6.15 MySQL 内连接查询
      • 6.16 MySQL 外连接查询
      • 6.17 MySQL 子查询
      • 6.18 MySQL 分组查询
      • 6.19 MySQL 指定过滤条件
      • 6.20 MySQL 正则表达式查询
    • 7. 函数
      • 7.1 常用函数
      • 7.2 聚合函数
      • 7.3 加密函数
      • 7.4 自定义函数
    • 8. 索引
      • 8.1 为什么要使用索引
      • 8.2 索引的分类
      • 8.3 索引的使用原则和注意事项
      • 8.4 创建索引
      • 8.5 修改和删除索引
    • 9. 用户权限管理
      • 9.1 创建用户
      • 9.2 修改用户
      • 9.3 删除用户
      • 9.4 用户授权
      • 9.5 删除用户权限
    • 10. 事务
    • 11. 数据库备份与恢复
      • 11.1 数据库备份
      • 11.2 数据库恢复

1. 操作数据库

操作数据库 > 操作数据库中的表 > 操作数据库中表的数据

1.1 创建数据库

数据库可以看作是一个专门存储数据对象的容器,这里的数据对象包括表、视图、触发器、存储过程等,其中表是最基本的数据对象。

1. 语法

在 MySQL 数据库中创建数据对象之前,先要创建好数据库。

在 MySQL 中,可以使用 CREATE DATABASE 语句创建数据库

1. 方式一:最简单的创建 MySQL 数据库的语句
CREATE DATABASE [IF NOT EXISTS] <数据库名>

2.方式二:创建 MySQL 数据库时指定字符集和校对规则
CREATE DATABASE IF NOT EXISTS <数据库名>
[CHARACTER SET<字符集名>] [COLLATE<校对规则名>];

[]中内容是可选的;

语法说明如下:

  • <数据库名>:创建数据库的名称。MySQL 的数据存储区将以目录方式表示 MySQL 数据库,因此数据库名称必须符合操作系统的文件夹命名规则,在 MySQL 中不区分大小写;

    引用:https://www.cnblogs.com/JBLi/p/10615999.html
    
    不能包含:< > / \ | :  * ? 
    1. 允许文件或者文件夹名称不得超过255个字符。
    2. 文件名除了开头之外任何地方都可以使用空格。
    3. 文件名中不能有下列符号:“?”、“、”、“/”、“╲”、“*”、“<”、“>”、“|”。
    4. Windows文件名不区分大小写,但在显示时可以保留大小写格式。
    5. 文件名中可以包含多个间隔符,如“我的文件。我的图片。001”。
    
  • IF NOT EXISTS :在创建数据库之前进行判断,只有该数据库目前尚不存在时才能执行操作。此选项可以用来避免数据库已经存在而重复创建的错误;

    此处就是方式 1 与方式 2 的不同之处,经过验证发现,如果需要指定字符集以及校对规则就不能对 IF NOT EXISTS 加括号,不然会提示创建语法错误,此处问题,没有找到相关原因,之后会留意相关资料,若找到,再回来进行详细说明。

  • CHARACTER SET:指定数据库默认的字符集。用来定义 MySQL 存储字符串的方式。

  • COLLATE:指定字符集的默认校对规则。定义了比较字符串的方式,解决排序和字符分组的问题。

    字符集和校对规则是一对多的关系,每个字符集至少对应一个校对规则。

    MySQL 支持 39 种字符集和 200 种左右的校对规则。

2. 实例

  • 最简单的创建 MySQL 数据库的语句:根据语法1,如下所示

    CREATE DATABASE IF NOT EXISTS `test01`;
    
  • 创建 MySQL 数据库时指定字符集和校对规则:根据语法2,如下所示

    CREATE DATABASE IF NOT EXISTS `test02`  CHARACTER SET utf8 COLLATE utf8_general_ci ;
    -- 指定默认字符集为 utf8
    -- 指定默认校对规则为 utf8_general_ci (不区分大小写) 
    
    

    为了防止字符混乱的情况发生,MySQL 有时需要在创建数据库时明确指定字符集;在中国大陆,常用哦的字符集有 utf8 和GBK;

    • utf8 能够存储全球的所有字符,在任何过国家都可以使用,默认的校对规则为 utf8_general_ci;
    • gbk 只能存储汉语涉及到的字符,不具有全球通用性,默认的校对规则为 gbk_chinese_ci;

1.2 查看数据库

1. 语法

在 MySQL 中,可使用 SHOW DATABASES 语句来查看或显示当前用户权限范围以内的数据库。

查看数据库的语法格式为:

SHOW DATABASES[LIKE '数据库名']

语法说明如下:

  • LIKE 是可选项,用于匹配指定的数据库名称。LIKE 语句可以部分匹配,也可以完全匹配。
  • 数据库名由单引号''包围。

2. 实例

  • 查看所有数据库

    mysql> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | school             |
    | sys                |
    | test01             |
    | test02             |
    +--------------------+
    7 rows in set (0.00 sec)
    
  • 使用 LIKE 语句

    • 使用 LIKE 语句,查看与 test01 完全匹配的数据库:

      mysql> show databases like 'test01';
      +-------------------+
      | Database (test01) |
      +-------------------+
      | test01            |
      +-------------------+
      1 row in set (0.00 sec)
      
    • 使用 LIKE 语句,查看名字中包含 test 的数据库:

      mysql> show databases like '%test%';
      +-------------------+
      | Database (%test%) |
      +-------------------+
      | test01            |
      | test02            |
      +-------------------+
      2 rows in set (0.00 sec)
      
    • 使用 LIKE 语句,查看名字以 s 开头的数据库:

      mysql> show databases like 's%';
      +---------------+
      | Database (s%) |
      +---------------+
      | school        |
      | sys           |
      +---------------+
      2 rows in set (0.00 sec)
      
    • 使用 LIKE 语句,查看名字以 l 结尾的数据库:

      mysql> show databases like '%l';
      +---------------+
      | Database (%l) |
      +---------------+
      | mysql         |
      | school        |
      +---------------+
      2 rows in set (0.00 sec)
      

1.3 修改数据库

1. 语法

在 MySQL 中,可以使用 ALTER DATABASEALTER SCHEMA 语句来修改已经被创建或者存在的数据库的相关参数。

修改数据库的语法格式为:

ALTER DATABASE [数据库名] 
{[DEFAULT] CHARACTER SET <字符集名> | [DEFAULT] COLLATE <校对规则名>};

语法说明如下:

  • ALTER DATABASE 用于更改数据库的全局特性。这些特性存储在数据库目录的 db.opt 文件中。

    (例如:D:\environment\mysql-5.7.19\data\test02\db.opt)

  • 使用 ALTER DATABASE 需要获得数据库 ALTER 权限。

  • 数据可名称可以忽略,此时语句对应于默认数据库。

  • CHARACTER SET 用于更改默认的数据库字符集。

  • COLLATE 用于更改默认的校对规则。

2. 实例

使用命令行工具将数据库 test01 的指定字符集修改为 gb2312,默认校对规则修改为 utf8_unicode_ci,输入 SQL 语句与执行结果如下所示:

mysql> ALTER DATABASE `test01`
    -> CHARACTER SET GB2312
    -> COLLATE gb2312_chinese_ci;
Query OK, 1 row affected (0.01 sec)

mysql> show create database test01;
+----------+-------------------------------------------------------------------+
| Database | Create Database                                                   |
+----------+-------------------------------------------------------------------+
| test01   | CREATE DATABASE `test01` /*!40100 DEFAULT CHARACTER SET gb2312 */ |
+----------+-------------------------------------------------------------------+
1 row in set (0.00 sec)

1.4 删除数据库

1.语法

在 MySQL 中,当需要删除已床架你的数据库时,可以使用 DROP DATABASEDROP SCHEMA 语句。

其语法格式为:

DROP DATABASE [IF EXISTS] <数据库名>

语法说明:

  • <数据库名>:指定要删除的数据库名。
  • IF EXISTS:用于防止当数据库不存在时发生错误。
  • DROP DATABASE:删除数据库中的所有表格并同时删除数据库。

注:MySQL 安装后,系统会自动创建名为 information_schema 和 mysql 的两个系统数据库,系统数据库存放一些 和数据库相关的信息,如果删除了这两个数据库,MySQL 将不能正常工作。

2. 实例

  • 显示目前所有的数据库:

    mysql> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | school             |
    | sys                |
    | test01             |
    | test02             |
    +--------------------+
    7 rows in set (0.00 sec)
    
  • 将数据库 test01 从数据库i而表中删除:

    mysql> drop database if exists test01;
    Query OK, 0 rows affected (0.02 sec)
    
    mysql> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | school             |
    | sys                |
    | test02             |
    +--------------------+
    6 rows in set (0.00 sec)
    

1.5 使用数据库

1. 语法

在 MySQL 中,USE 语句用来完成一个数据库到另一个数据库的跳转;

当用 CREATE DATABASE 语句创建数据库之后,该数据库不会自动成为当前数据库,需要用 USE 来指定当前数据库。

其语法格式为:

USE<数据库名>

该语句可以通知 MySQL 把<数据库名>所指示的数据库作为当前数据库。

该数据库保持为默认数据库,直到语段的结尾,或者直到遇见一个不同的 USE 语句。

只有使用 USE 语句来指定某个数据库作为当前数据库之后,才能对该数据库及其存储的数据对象执行操作。

2. 实例

  • 将数据库 school 设置为默认数据库

    mysql> use school;
    Database changed
    

2. MySQL 存储引擎

2.1 什么是存储引擎

数据库的存储引擎是数据库底层软件组件,数据库管理系统使用数据引擎进行创建、查询、更新和删除数据操作。

不同的存储引擎提供不同的存储机制、索引技巧、锁定水平功能,使用不同的存储引擎还可以获得特定的功能。

现在许多数据库管理系统都支持多种不同的存储引擎。

MySQL 的核心就是存储引擎。

InnoDB 事务型数据库是首选推荐,支持事务安全表(ACID),支持行锁定和外键。MySQL 5.5.5 之后,InnoDB 作为默认的存储引擎。

MEMORY 存储引擎将表中的数据存储到内存中,为查询和引用其他数据提供快速访问。

2.2 MySQL 5.7 支持的存储引擎

MySQL 支持多种类型的数据库引擎,可分别根据各个引擎的功能和特性为不同的数据库处理任务提供各自不同的适应性和灵活性。

在 MySQL 中,可以利用 SHOW ENGINES 语句来显示可用的数据库引擎和默认引擎。

MySQL 提供了多个不同的存储引擎,包括处理事务安全表的引擎和处理非事务安全表的引擎。

在 MySQL 中,不需要在整个服务器中使用同一种存储引擎,针对具体的要求,可以对每一个表使用不同的存储引擎。
MySQL_第1张图片Support 列的值表示某种引擎是否能使用,YES表示可以使用,NO表示不能使用,DEFAULT表示该引擎为当前默认的存储引擎。

2.3 如何选择 MySQL 存储引擎

不同的存储引擎都有各自的特带你,以适应不同的需求,如表所示。

功能 MylSAM MEMORY InnoDB Archive
存储限制 256TB RAM 64TB None
支持事务 No No Yes No
支持全文索引 Yes No No No
支持树索引 Yes Yes Yes No
支持哈希索引 No Yes No No
支持数据缓存 No N/A Yes No
支持外键 No No Yes No

可以根据一下的原则来选择 MySQL 存储引擎:

  • 如果要提供提交、回滚和恢复的事务安全(ACID 兼容)能力,并要求实现并发控制,InnoDB 是一个很好的选择;
  • 如果数据表主要用来插入和查询记录,则 MyISAM 引擎提供较高的处理效率;
  • 如果只是临时存放数据,数据量不大,并且不需要较高的数据安全性,可以选择将数据保存在内存的 MEMORY 引擎中, MySQL 中使用该引擎作为临时表,存放查询的中间结果;
  • 如果只有 INSERT 和 SELECT 操作,可以选择 Archive 引擎,Archive 存储引擎支持高并发的插入操作,但本身并不是事务安全的。Archive 存储引擎非常适合存储归档的书,如记录日志信息可以使用 Archive 引擎。

3. MySQL 常见数据类型

数据类型(data_type)是指系统中所允许的数据的类型。

数据库中的每个列都应该有适当的数据类型,用于限制或允许该列中存储的数据。例如,列中存储的为数字,则相应的数据类型应该为数值类型。

使用数据类型i有助于对数据进行正确排序,并在优化磁盘使用方面起着重要的作用。因此,在创建表时必须为每个列设置正确的数据类型及可能的长度。

在 MySQL 中常见的数据类型如下:

整数类型

包括 TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,浮点数类型 FLOAT 和 DOUBLE,定点数类型 DECIMAL。

时间/日期类型

包括 YEAR、TIME、DATE、DATETIME 和 TIMESTAMP。

字符串类型

包括 CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM 和 SET 等。

二进制类型

包括 BIT、BINARY、VARBINARY、TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。

3.1 整数类型

整数类型又称数值型数据,数值型数据类型主要用来存储数字

MySQL 提供了多种数值型数据类型,不同的数据类型提供不同的取值范围,可以存储的值范围越大,所需的存储空间也会越大。

MySQL 主要提供的整数类型有 TINYINTPLANETESIMALMEDIUMINTINTBIGINT,其属性字段可以添加 AUTO_INCREMENT 自增约束条件。下表中列出了 MySQL 中的数值类型。

类型名称 说明 存储需求
TINYINT 很小的整数 1个字节
SMALLINT 小的整数 2个宇节
MEDIUMINT 中等大小的整数 3个字节
INT (INTEGHR) 普通大小的整数 4个字节
BIGINT 大整数 8个字节

根据占用字节数可以求出每一种数据类型的取值范围。例如,TINYINT 需要 1 个字节(8 bit)来存储,那么 TINYINT 无符号数的最大值为 2^8-1,即 255;TINYINT 有符号数的最大值为 2^7-1,即 127。其他类型的整数的取值范围计算方法相同,如下表所示。

类型名称 说明 存储需求
TINYINT -128〜127 0 〜255
SMALLINT -32768〜32767 0〜65535
MEDIUMINT -8388608〜8388607 0〜16777215
INT (INTEGER) -2147483648〜2147483647 0〜4294967295
BIGINT -9223372036854775808〜9223372036854775807 0〜18446744073709551615

3.2 小数类型

MySQL 中使用浮点数和定点数来表示小数。

浮点数有两种类型,分别是单精度浮点数(FLOAT)和双精度浮点数(DOUBLE);

定点类型只有一种,就是 DECIMAL

浮点数和定点数都可以用(M,D)来表示,其中M称为精度,表示总共的位数;D称为标度,表示小数的位数。

浮点数类型的取值范围为 M (1 ~ 255) 和 D (1 ~ 30,且不能大于 M-2),分别表示显示宽度和小数位数。

M 和 D 在 FLOAT 和 DOUBLE 中时可选的, FLOAT 和 DOUBLE 类型将被保存为硬件所支持的最大精度;

DECIMAL 的默认 D 值是0, M 值为 10。

类型名称 说明 存储需求
FLOAT 单精度浮点数 4 个字节
DOUBLE 双精度浮点数 8 个字节
DECIMAL (M, D),DEC 压缩的“严格”定点数 M+2 个字节

DECIMAL 类型不同于 FLOAT 和 DOUBLE。

DOUBLE 实际上是以字符串的形式存放的,DECIMAL 可能的最大取值范围与 DOUBLE 相同,但是有效的取值范围由 M 和 D 决定。

如果改变 M 而固定 D,则取值范围将随 M 的变大而变大。

FLOAT 类型的取值范围如下:

  • 有符号的取值范围:-3.402823466E+38~-1.175494351E-38。
  • 无符号的取值范围:0 和 -1.175494351E-38~-3.402823466E+38。

DOUBLE 类型的取值范围如下:

  • 有符号的取值范围:-1.7976931348623157E+308~-2.2250738585072014E-308。
  • 无符号的取值范围:0 和 -2.2250738585072014E-308~-1.7976931348623157E+308。

提示:不论是定点还是浮点类型,如果用户指定的精度超出精度范围,则会四舍五入进行处理。

浮点数相对于定点数的优点是在长度一定的情况下,浮点数能够表示更大的范围;缺点是会引起精度问题。

在 MySQL 中,定点数以字符串形式存储,在对精度要求比较高的时候(如货币、科学数据),使用 DECIMAL 的类型比较好,另外两个浮点数进行减法和比较运算时也容易出问题,所以在使用浮点数时需要注意,并尽量避免做浮点数比较。

3.3 日期/时间类型

MySQL 中有多处表示日期的数据类型:YEARTIMEDATEDATETIMETIMESTAMP。当只记录年信息的时候,可以只使用 YEAR 类型。

每一个类型都有合法的取值范围,当指定确定不合法的值时,系统将“零”值插入数据库中。

类型名称 日期格式 日期范围 存储需求
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-3 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 1980-01-01 00:00:01 UTC ~ 2040-01-19 03:14:07 UTC 4 个字节

1. YEAR 类型

YEAR 类型是一个单字节类型,用于表示年,在存储时只需要 1 个字节。可以使用各种格式指定 YEAR,如下所示:

  • 以 4 位字符串或者 4 位数字格式表示的 YEAR,范围为 ‘1901’~’2155’。输入格式为 ‘YYYY’ 或者 YYYY,例如,输入 ‘2010’ 或 2010,插入数据库的值均为 2010。

  • 以 2 位字符串格式表示的 YEAR,范围为 ‘00’ 到 ‘99’。‘00’~’69’ 和 ‘70’~’99’ 范围的值分别被转换为 2000~2069 和 1970~1999 范围的 YEAR 值。‘0’ 与 ‘00’ 的作用相同。插入超过取值范围的值将被转换为 2000。

  • 以 2 位数字表示的 YEAR,范围为 1~99。1~99 和 70~99 范围的值分别被转换为 2001~2069 和 1970~1999 范围的 YEAR 值。注意,在这里 0 值将被转换为 0000,而不是 2000。

    -- 创建一张表
    CREATE TABLE timeTest1(
    	d1 YEAR
    )
    -- 以 4 位字符串或者 4 位数字格式表示的 YEAR
    INSERT INTO timeTest1 VALUES ('1901'),(2014)
    
    -- 以 2 位字符串格式表示的 YEAR
    INSERT INTO timeTest1 VALUES ('68'),('89')
    
    -- 以 2 位数字表示的 YEAR
    INSERT INTO timeTest1 VALUES (68),(89)
    
    -- 插入  2000
    -- 数字插入
    INSERT INTO timeTest1 VALUES (0)
    
    -- 字符串插入
    INSERT INTO timeTest1 VALUES ('0')
    

    结果:
    MySQL_第2张图片

2. TIME 类型

TIME 类型用于只需要时间信息的值,在存储时需要 3 个字节。格式为 HH:MM:SS。HH 表示小时,MM 表示分钟,SS 表示秒。

TIME 类型的取值范围为 -838:59:59~838:59:59,小时部分如此大的原因是 TIME 类型不仅可以用于表示一天的时间(必须小于 24 小时),还可能是某个事件过去的时间或两个事件之间的时间间隔(可大于 24 小时,或者甚至为负)。

可以使用各种格式指定 TIME 值,如下所示。

  • ‘D HH:MM:SS’ 格式的字符串。还可以使用这些“非严格”的语法:‘HH:MM:SS’、‘HH:MM’、‘D HH’ 或 ‘SS’。这里的 D 表示日,可以取 0~34 (838/24)之间的值。在插入数据库时,D 被转换为小时保存,格式为 “D*24+HH”。
  • ‘HHMMSS’ 格式、没有间隔符的字符串或者 HHMMSS 格式的数值,假定是有意义的时间。例如,‘101112’ 被理解为’10:11:12’,但是 ‘106112’ 是不合法的(它有一个没有意义的分钟部分),在存储时将变为 00:00:00。

为 TIME 列分配简写值时应注意:如果没有冒号,MySQL 解释值时,假定最右边的两位表示秒。(MySQL 解释 TIME 值为过去的时间而不是当前的时间)。例如,读者可能认为 ‘1112’ 和 1112 表示 11:12:00(即 11 点过 12 分钟),但MySQL 将它们解释为 00:11:12(即 11 分 12 秒)。同样 ‘12’ 和 12 被解释为00:00:12。相反,TIME 值中如果使用冒号则肯定被看作当天的时间,也就是说,‘11:12’ 表示 11:12:00,而不是 00:11:12。

CREATE TABLE timeTset2(
	d2 TIME
)

-- 'D HH:MM:SS' 格式的字符串
INSERT INTO timeTset2 VALUES('2 01:01:01')

-- 非严格语法:'HH:MM:SS'、'HH:MM'、'D HH' 或 'SS'
INSERT INTO timeTset2 VALUES('01:01:01'), ('01:01'),('2 01'), ('01')

-- 'HHMMSS' 格式、没有间隔符的字符串或者 HHMMSS 格式的数值
INSERT INTO timeTset2 VALUES('02:02:02'),('020202')

-- 如果没有冒号,MySQL 解释值时,假定最右边的两位表示秒
INSERT INTO timeTset2 VALUES('1112'),(1112)

-- TIME 值中如果使用冒号则肯定被看作当天的时间
INSERT INTO timeTset2 VALUES('11:12')

结果:
MySQL_第3张图片

3. DATE 类型

DATE 类型用于仅需要日期值时,没有时间部分,在存储时需要 3 个字节。日期格式为 ‘YYYY-MM-DD’,其中 YYYY 表示年,MM 表示月,DD 表示日。

在给 DATE 类型的字段赋值时,可以使用字符串类型或者数字类型的数据插入,只要符合 DATE 的日期格式即可。如下所示:

  • 以 ‘YYYY-MM-DD’ 或者 ‘YYYYMMDD’ 字符中格式表示的日期,取值范围为 ‘1000-01-01’~’9999-12-3’。例如,输入 ‘2015-12-31’ 或者 ‘20151231’,插入数据库的日期为2015-12-31。
  • 以 ‘YY-MM-DD’ 或者 ‘YYMMDD’ 字符串格式表示日期,在这里YY表示两位的年值。MySQL 解释两位年值的规则:‘00~69’ 范围的年值转换为 ‘2000 ~ 2069’,‘70~99’ 范围的年值转换为 ‘1970~1999’。例如,输入 ‘15-12-31’,插入数据库的日期为 2015-12-31;输入 ‘991231’,插入数据库的日期为 1999-12-31。
  • 以 YYMMDD 数字格式表示的日期,与前面相似,00~69 范围的年值转换为 2000~2069,80~99 范围的年值转换为 1980~1999。例如,输入 151231,插入数据库的日期为 2015-12-31,输入 991231,插入数据库的日期为 1999-12-31。
  • 使用 CURRENT_DATE 或者 NOW(),插入当前系统日期。
CREATE TABLE timeTest3(	
	d3 DATE
)

-- 以 'YYYY-MM-DD' 或者 'YYYYMMDD' 字符中格式表示的日期
INSERT INTO timeTest3 VALUES('20151231'),('2015-12-31')

-- 以 'YY-MM-DD' 或者 'YYMMDD' 字符串格式表示日期
INSERT INTO timeTest3 VALUES('15-12-31'),('991231')

-- 以 YYMMDD 数字格式表示的日期
INSERT INTO timeTest3 VALUES(151231),(991231)

-- 使用 CURRENT_DATE 或者 NOW()
INSERT INTO timeTest3 VALUES (CURRENT_DATE)
INSERT INTO timeTest3 VALUES (NOW())

结果:
MySQL_第4张图片

4. DATETIME 类型

DATETIME 类型用于需要同时包含日期和时间信息的值,在存储时需要 8 个字节。日期格式为 ‘YYYY-MM-DD HH:MM:SS’,其中 YYYY 表示年,MM 表示月,DD 表示日,HH 表示小时,MM 表示分钟,SS 表示秒。

在给 DATETIME 类型的字段赋值时,可以使用字符串类型或者数字类型的数据插入,只要符合 DATETIME 的日期格式即可,如下所示。

  • 以 ‘YYYY-MM-DD HH:MM:SS’ 或者 ‘YYYYMMDDHHMMSS’ 字符串格式表示的日期,取值范围为 ‘1000-01-01 00:00:00’~’9999-12-3 23:59:59’。例如,输入 ‘2014-12-31 05:05:05’ 或者 '20141231050505’,插入数据库的 DATETIME 值都为 2014-12-31 05:05:05。
  • 以 ‘YY-MM-DD HH:MM:SS’ 或者 ‘YYMMDDHHMMSS’ 字符串格式表示的日期,在这里 YY 表示两位的年值。与前面相同,‘00~79’ 范围的年值转换为 ‘2000~2079’,‘80~99’ 范围的年值转换为 ‘1980~1999’。例如,输入 ‘14-12-31 05:05:05’,插入数据库的 DATETIME 为 2014-12-31 05:05:05;输入 141231050505,插入数据库的 DATETIME 为 2014-12-31 05:05:05。
  • 以 YYYYMMDDHHMMSS 或者 YYMMDDHHMMSS 数字格式表示的日期和时间。例如,输入 20141231050505,插入数据库的 DATETIME 为 2014-12-31 05:05:05;输入 140505050505,插入数据库的 DATETIME 为 2014-12-31 05:05:05。
CREATE TABLE timeTest4(
	d4 DATETIME
)

-- 以 'YYYY-MM-DD HH:MM:SS' 或者 'YYYYMMDDHHMMSS' 字符串格式表示的日期
INSERT INTO timeTest4 VALUES('2014-12-31 05:05:05'),('20141231050505')

-- 以 'YY-MM-DD HH:MM:SS' 或者 'YYMMDDHHMMSS' 字符串格式表示的日期
INSERT INTO timeTest4 VALUES('14-12-31 05:05:05'),('141231050505')

-- 以 YYYYMMDDHHMMSS 或者 YYMMDDHHMMSS 数字格式表示的日期和时间
INSERT INTO timeTest4 VALUES(20141231050505),(140505050505)

结果:
MySQL_第5张图片

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。在插入数据时,要保证在合法的取值范围内。

提示:协调世界时(英:Coordinated Universal Time,法:Temps Universel Coordonné)又称为世界统一时间、世界标准时间、国际协调时间。英文(CUT)和法文(TUC)的缩写不同,作为妥协,简称 UTC。

TIMESTAMP 与 DATETIME 除了存储字节和支持的范围不同外,还有一个最大的区别是:

  • DATETIME 在存储日期数据时,按实际输入的格式存储,即输入什么就存储什么,与时区无关;
  • 而 TIMESTAMP 值的存储是以 UTC(世界标准时间)格式保存的,存储时对当前时区进行转换,检索时再转换回当前时区。即查询时,根据当前时区的不同,显示的时间值是不同的。

提示:如果为一个 DATETIME 或 TIMESTAMP 对象分配一个 DATE 值,结果值的时间部分被设置为 ‘00:00:00’,因此 DATE 值未包含时间信息。如果为一个 DATE 对象分配一个 DATETIME 或 TIMESTAMP 值,结果值的时间部分被删除,因此DATE 值未包含时间信息。

3.4 字符串类型

字符串类型用来存储字符串数据,还可以存储图片和声音的二进制数据。字符串可以区分或者不区分大小写的串比较,还可以进行正则表达式的匹配查找。

MySQL 中的字符串类型有 CHARVARCHARTINYTEXTTEXTMEDIUMTEXTLONGTEXTENUMSET 等。

下表中列出了 MySQL 中的字符串数据类型,括号中的M表示可以为其指定长度。

VARCHAR 和 TEXT 类型是变长类型,其存储需求取决于列值的实际长度(表格中用 L表示),而不是取决于类型的最大可能尺寸。

类型名称 说明 存储需求
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(10) 列能保存一个最大长度为 10 个字符的字符串,实际的存储需要字符串的长度 L 加上一个字节以记录字符串的长度。对于字符 “abcd”,L 是 4,而存储要求 5 个字节。

1. CHAR 和 VARCHAR 类型

  • CHAR(M) 为固定长度字符串,在定义时指定字符串列长。当保存时,在右侧填充空格以达到指定的长度。M 表示列的长度,范围是 0~255 个字符。

    例如,CHAR(4) 定义了一个固定长度的字符串列,包含的字符个数最大为 4。当检索到 CHAR 值时,尾部的空格将被删除。

  • VARCHAR(M) 是长度可变的字符串,M 表示最大列的长度,M 的范围是 0~65535。VARCHAR 的最大实际长度由最长的行的大小和使用的字符集确定,而实际占用的空间为字符串的实际长度加 1。

    例如,VARCHAR(50) 定义了一个最大长度为 50 的字符串,如果插入的字符串只有 10 个字符,则实际存储的字符串为 10 个字符和一个字符串结束字符。VARCHAR 在值保存和检索时尾部的空格仍保留。

【实例】下面将不同的字符串保存到 CHAR(4) 和 VARCHAR(4) 列,说明 CHAR 和 VARCHAR 之间的差别,如下表所示。

插入值 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字节

对比结果可以看到,CHAR(4) 定义了固定长度为 4 的列,无论存入的数据长度为多少,所占用的空间均为 4 个字节。VARCHAR(4) 定义的列所占的字节数为实际长度加 1。

2. TEXT 类型

TEXT 列保存非二进制字符串,如文章内容、评论等。当保存或查询 TEXT 列的值时,不删除尾部空格。

TEXT 类型分为 4 种:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。不同的 TEXT 类型的存储空间和数据长度不同。

  • TINYTEXT 表示长度为 255(2^8-1)字符的 TEXT 列。
  • TEXT 表示长度为 65535(2^16-1)字符的 TEXT 列。
  • MEDIUMTEXT 表示长度为 16777215(2^24-1)字符的 TEXT 列。
  • LONGTEXT 表示长度为 4294967295 或 4GB(2^32-1)字符的 TEXT 列。

3. ENUM 类型

ENUM 是一个字符串对象,值为表创建时列规定中枚举的一列值。其语法格式如下:

<字段名> ENUM( '值1', '值1', …, '值n' )

字段名指将要定义的字段,值 n 指枚举列表中第 n 个值。

ENUM 类型的字段在取值时,能在指定的枚举列表中获取,而且一次只能取一个。如果创建的成员中有空格,尾部的空格将自动被删除。

ENUM 值在内部用整数表示,每个枚举值均有一个索引值;列表值所允许的成员值从 1 开始编号,MySQL 存储的就是这个索引编号,枚举最多可以有 65535 个元素。

例如,定义 ENUM 类型的列(‘first’,‘second’,‘third’),该列可以取的值和每个值的索引如下表所示。

索引
NULL NULL
‘’ 0
first 1
second 2
third 3

ENUM 值依照列索引顺序排列,并且空字符串排在非空字符串前,NULL 值排在其他所有枚举值前。

提示:ENUM 列总有一个默认值。如果将 ENUM 列声明为 NULL,NULL 值则为该列的一个有效值,并且默认值为 NULL。如果 ENUM 列被声明为 NOT NULL,其默认值为允许的值列表的第 1 个元素。

4. SET 类型

SET 是一个字符串的对象,可以有零或多个值,SET 列最多可以有 64 个成员,值为表创建时规定的一列值。指定包括多个 SET 成员的 SET 列值时,各成员之间用逗号,隔开,语法格式如下:

SET( '值1', '值2', …, '值n' )

与 ENUM 类型相同,SET 值在内部用整数表示,列表中每个值都有一个索引编号。当创建表时,SET 成员值的尾部空格将自动删除。

但与 ENUM 类型不同的是,ENUM 类型的字段只能从定义的列值中选择一个值插入,而 SET 类型的列可从定义的列值中选择多个字符的联合。

提示:如果插入 SET 字段中的列值有重复,则 MySQL 自动删除重复的值;插入 SET 字段的值的顺序并不重要,MySQL 会在存入数据库时,按照定义的顺序显示;如果插入了不正确的值,默认情况下,MySQL 将忽视这些值,给出警告。

4. 数据库的字段属性

Unsigned:

  • 无符号的整数
  • 声明了该列不能声明为负数

zerofill:

  • 0 填充的
  • 不足的位数,使用 0 来填充, int(3), 例如:5 —> 005

自增:

  • 通常理解为自增,自动在上一条记录的基础上 + 1 (默认)
  • 通常用来设计唯一的主键 ~ index,必须是整数类型
  • 可以自定义设计主键自增的起始值和步长

非空

  • Null :如果不填写,默认值就是null
  • not null, 如果不给他赋值,就会报错。

默认

  • 设置默认的值。
  • sex 默认为男,如果不指定该列的值,则会有默认的值:男。

每一个表,都必须存在以下五个字段;

  • id 主键
  • version 乐观锁
  • is_delete 伪删除
  • gmt_create 创建时间
  • gmt_update 修改时间

5.操作数据库表

5.1 创建数据库表

在创建数据库之后,接下来就要在数据库中创建数据表。所谓创建数据表,指的是在已经创建的数据库中建立新表。

创建数据表的过程是规定数据列的属性的过程,同时也是实施数据完整性(包括实体完整性、引用完整性和域完整性)约束的过程。接下来我们介绍一下创建数据表的语法形式。

1. 基本语法

在 MySQL 中,可以使用 CREATE TABLE语句来创建表。

其格式语法为:

CREATE TABLE IF NOT EXISTS `表名`(
	`字段名` 列表型 [属性] [索引] [注释],
	`字段名` 列表型 [属性] [索引] [注释],
			······
	`字段名` 列表型 [属性] [索引] [注释]
)[表类型][字符集设置][注释]

CREATE TABLE 语句的主要语法及使用说明如下:

  • CREATE TABLE:用于创建给定名称的表,必须拥有表CREATE的权限。
  • <表名>:指定要创建表的名称,在 CREATE TABLE 之后给出,必须符合标识符命名规则。表名称被指定为 db_name.tbl_name,以便在特定的数据库中创建表。无论是否有当前数据库,都可以通过这种方式创建。在当前数据库中创建表时,可以省略 db-name。如果使用加引号的识别名,则应对数据库和表名称分别加引号。例如,‘mydb’.‘mytbl’ 是合法的,但 ‘mydb.mytbl’ 不合法。
  • 默认的情况是,表被创建到当前的数据库中。若表已存在、没有当前数据库或者数据库不存在,则会出现错误。

提示:使用 CREATE TABLE 创建表时,必须指定以下信息:

  • 要创建的表的名称不区分大小写,不能使用SQL语言中的关键字,如DROP、ALTER、INSERT等。
  • 数据表中每个列(字段)的名称和数据类型,如果创建多个列,要用逗号隔开。

2. 在指定数据库中创建表

数据表属于数据库,在创建数据表之前,应使用语句“USE<数据库>”指定操作在哪个数据库中进行,如果没有选择数据库,就会抛出 No database selected 的错误。

-- 目标:在school 数据库中创建 student 表(使用 SQL 创建)
-- 学号 int,登录密码 varchar(20) 姓名、性别 varchar(2),出生日期(datatime),家庭住址,email

-- 注意点:
-- 使用英文(),表的名称和 字段尽量使用 `` 括起来
-- AUTO-INCREMENT 自增
-- 字符串使用 '' (单引号)括起来
-- 所有的语句后面加英文逗号 , 最后一个不加
-- PRIMARY KRY 主键,一般一个表只有一个唯一的主键


USE school

CREATE TABLE IF NOT EXISTS `student`(
	`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
	`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
	`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
	`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
	`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
	`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
	`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
	PRIMARY KEY(`id`)
)ENGINE = INNODB DEFAULT CHARSET = utf8

结果:
MySQL_第6张图片
3. 查看表结构

在 MySQL 中,使用 SQL 语句创建好数据表之后,可以查看结构的定义,以确认表的定义是否正确。在 MySQL 中,查看表结构可以使用 DESCRIBE 和 SHOW CREATE TABLE 语句。

DESCRIBE/DESC 语句可以查看表的字段信息,包括字段名、字段数据类型、是否为主键、是否有默认值等,语法规则如下:

DESCRIBE <表名>;

或简写成:

DESC <表名>;

实例:

DESCRIBE student

结果:
MySQL_第7张图片

其中,各个字段的含义如下:

  • Null:表示该列是否可以存储 NULL 值。
  • Key:表示该列是否已编制索引。PRI 表示该列是表主键的一部分,UNI 表示该列是 UNIQUE 索引的一部分,MUL 表示在列中某个给定值允许出现多次。
  • Default:表示该列是否有默认值,如果有,值是多少。
  • Extra:表示可以获取的与给定列有关的附加信息,如 AUTO_INCREMENT 等。

SHOW CREATE TABLE语句可以用来显示创建表时的CREATE TABLE语句,语法格式如下:

SHOW CREATE TABLE <表名>\G;

实例:

  • 使用 sqlyog
SHOW CREATE TABLE student
-- 此处使用的是sqlyog

​ 结果:此处使用的是 sqlyog,需要将红色部分复制然后黏贴在窗口,如下所示:
MySQL_第8张图片

  • 使用命令行模式:

    mysql> use school;
    Database changed
    mysql> show create table student\G
    *************************** 1. row ***************************
           Table: student
    Create Table: CREATE TABLE `student` (
      `id` int(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
      `name` varchar(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
      `pwd` varchar(20) NOT NULL DEFAULT '123456' COMMENT '密码',
      `sex` varchar(2) NOT NULL DEFAULT '女' COMMENT '性别',
      `birthday` datetime DEFAULT NULL COMMENT '出生日期',
      `address` varchar(100) DEFAULT NULL COMMENT '家庭住址',
      `email` varchar(50) DEFAULT NULL COMMENT '邮箱',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    1 row in set (0.00 sec)
    

    提示:使用 SHOW CREATE TABLE 语句不仅可以查看创建表时的详细语句,而且可以查看存储引擎和字符编码。如果不加“\G”参数,显示的结果可能非常混乱,加上“\G”参数之后,可使显示的结果更加直观,易于查看。

5.2 修改数据表

为了实现数据库中表规范化设计的目的,有时候需要对之前已经创建的表进行结构修改或者调整。

在 MySQL 中可以使用 ALTER TABLE 语句来改变原有表的结构,例如增加或删除列、创建或取消索引、更改原有列的类型、重命名列或表等。

1. 基本语法

修改表指的是修改数据库中已经存在的数据表的结构。MySQL 使用 ALTER TABLE 语句修改表。常用的修改表的操作有修改表名、修改字段数据类型或字段名、增加和删除字段、修改字段的排列位置、更改表的存储引擎、删除表的外键约束等。

常用的语法格式如下:

ALTER TABLE <表名> { ADD COLUMN <列名> <类型>
| CHANGE COLUMN <旧列名> <新列名> <新列类型>
| ALTER COLUMN <列名> { SET DEFAULT <默认值> | DROP DEFAULT }
| MODIFY COLUMN <列名> <类型>
| DROP COLUMN <列名>
| RENAME TO <新表名> }

2. 添加字段

随着业务的变化,可能需要在已经存在的表中添加新的字段,一个完整的字段包括字段名、数据类型、完整性约束。添加字段的语法格式如下:

ALTER TABLE <表名> ADD <新字段名><数据类型>[约束条件][FIRST|AFTER 已存在的字段名]

说明:

新字段名:为需要添加的字段的名称;

FIRST:可选参数,其作用是将新添加的字段设置为表的第一个字段;

AFTER:可选参数,起作用是将新添加的字段添加到指定的已存在的字段名的后面。

实例1:使用 ALTER TABLE 修改表 student 的结构,在表的第一列添加一个 int 类型的字段 col1 ,输入的 SQL 语句和运行结果如下所示:

  • 命令行模式:

    mysql> alter table student
        -> add column col1 int first;
    Query OK, 0 rows affected (1.74 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> desc student;
    +----------+--------------+------+-----+---------+----------------+
    | Field    | Type         | Null | Key | Default | Extra          |
    +----------+--------------+------+-----+---------+----------------+
    | col1     | int(11)      | YES  |     | NULL    |                |
    | id       | int(4)       | NO   | PRI | NULL    | auto_increment |
    | name     | varchar(30)  | NO   |     | 匿名    |                |
    | pwd      | varchar(20)  | NO   |     | 123456  |                |
    | sex      | varchar(2)   | NO   |     ||                |
    | birthday | datetime     | YES  |     | NULL    |                |
    | address  | varchar(100) | YES  |     | NULL    |                |
    | email    | varchar(50)  | YES  |     | NULL    |                |
    +----------+--------------+------+-----+---------+----------------+
    8 rows in set (0.00 sec)
    
    mysql>
    

    提示:“FIRST 或 AFTER 已存在的字段名”用于指定新增字段在表中的位置,如果 SQL 语句中没有这两个参数,则默认将新添加的字段设置为数据表的最后列。

  • sqlyog:

    ALTER TABLE student ADD COLUMN col2 INT FIRST;
    DESC student
    

结果:
MySQL_第9张图片

3. 修改字段数据类型

修改字段的数据类型就是把字段的数据类型转换成另一种数据类型。在 MySQL 中修改字段数据类型的语法规则如下:

ALTER TABLE <表名> MODIFY <字段名> <数据类型>

其中,

表名:指要修改数据类型的字段所在表的名称,

字段名:指需要修改的字段,

数据类型:指修改后字段的新数据类型。

实例:使用 ALTER TABLE 修改表 student 的结构,将 name 字段的数据类型由 VARCHAR(30) 修改成 VARCHAR(20),输入的 SQL 语句和运行结果如下所示。

  • 命令行模式:

    mysql> alter table student
        -> modify name varchar(20);
    Query OK, 0 rows affected (1.23 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> desc student;
    +----------+--------------+------+-----+---------+----------------+
    | Field    | Type         | Null | Key | Default | Extra          |
    +----------+--------------+------+-----+---------+----------------+
    | col2     | int(11)      | YES  |     | NULL    |                |
    | col1     | int(11)      | YES  |     | NULL    |                |
    | id       | int(4)       | NO   | PRI | NULL    | auto_increment |
    | name     | varchar(20)  | YES  |     | NULL    |                |
    | pwd      | varchar(20)  | NO   |     | 123456  |                |
    | sex      | varchar(2)   | NO   |     ||                |
    | birthday | datetime     | YES  |     | NULL    |                |
    | address  | varchar(100) | YES  |     | NULL    |                |
    | email    | varchar(50)  | YES  |     | NULL    |                |
    +----------+--------------+------+-----+---------+----------------+
    9 rows in set (0.01 sec)
    
  • sqlyog:

    ALTER TABLE student MODIFY NAME VARCHAR(20);
    DESC student
    

    结果:
    MySQL_第10张图片

4. 删除字段

删除字段是将数据表中的某个字段从表中移除,语法格式如下:

ALTER TABLE <表名> DROP <字段名>

其中,

字段名:指需要从表中删除的字段的名称。

实例:使用 ALTER TABLE 修改表 student 的结构,删除 col2 字段,输入的 SQL 语句和运行结果如下所示。

  • 命令行模式:

    mysql> alter table student
        -> drop col2;
    Query OK, 0 rows affected (1.10 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> desc student;
    +----------+--------------+------+-----+---------+----------------+
    | Field    | Type         | Null | Key | Default | Extra          |
    +----------+--------------+------+-----+---------+----------------+
    | col1     | int(11)      | YES  |     | NULL    |                |
    | id       | int(4)       | NO   | PRI | NULL    | auto_increment |
    | name     | varchar(20)  | YES  |     | NULL    |                |
    | pwd      | varchar(20)  | NO   |     | 123456  |                |
    | sex      | varchar(2)   | NO   |     ||                |
    | birthday | datetime     | YES  |     | NULL    |                |
    | address  | varchar(100) | YES  |     | NULL    |                |
    | email    | varchar(50)  | YES  |     | NULL    |                |
    +----------+--------------+------+-----+---------+----------------+
    8 rows in set (0.00 sec)
    
  • sqlyog:

    ALTER TABLE student DROP col2;
    DESC student
    

    结果:
    MySQL_第11张图片

5. 修改字段名称

MySQL 中修改表字段名的语法规则如下:

ALTER TABLE <表名> CHANGE <旧字段名> <新字段名> <新数据类型>

其中,

旧字段名:指修改前的字段名;

新字段名:指修改后的字段名;

新数据类型:指修改后的数据类型,如果不需要修改字段的数据类型,可以将新数据类型设置成与原来一样,但数据类型不能为空。

实例 :使用 ALTER TABLE 修改表 student1 的结构,将 col1 字段名称改为 col3,同时将数据类型变为 CHAR(30),输入的 SQL 语句和运行结果如下所示。

  • 命令行模式:

    mysql> alter table student
        -> change col1 col3 char(30);
    Query OK, 0 rows affected (1.32 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> desc student;
    +----------+--------------+------+-----+---------+----------------+
    | Field    | Type         | Null | Key | Default | Extra          |
    +----------+--------------+------+-----+---------+----------------+
    | col3     | char(30)     | YES  |     | NULL    |                |
    | id       | int(4)       | NO   | PRI | NULL    | auto_increment |
    | name     | varchar(20)  | YES  |     | NULL    |                |
    | pwd      | varchar(20)  | NO   |     | 123456  |                |
    | sex      | varchar(2)   | NO   |     ||                |
    | birthday | datetime     | YES  |     | NULL    |                |
    | address  | varchar(100) | YES  |     | NULL    |                |
    | email    | varchar(50)  | YES  |     | NULL    |                |
    +----------+--------------+------+-----+---------+----------------+
    8 rows in set (0.01 sec)
    

    CHANGE 也可以只修改数据类型,实现和 MODIFY 同样的效果,方法是将 SQL 语句中的“新字段名”和“旧字段名”设置为相同的名称,只改变“数据类型”。

    提示:由于不同类型的数据在机器中的存储方式及长度并不相同,修改数据类型可能会影响数据表中已有的数据记录,因此,当数据表中已经有数据时,不要轻易修改数据类型。

  • sqlyog:

    ALTER TABLE student CHANGE col1 col3 CHAR(30);
    DESC student
    

    结果:
    MySQL_第12张图片

6. 修改表名

MySQL 通过 ALTER TABLE 语句来实现表名的修改,语法规则如下:

ALTER TABLE <旧表名> RENAME [TO] <新表名>

其中,TO 为可选参数,使用与否均不影响结果。

实例:使用 ALTER TABLE 将数据表 student 改名为 studentChange,输入的 SQL 语句和运行结果如下所示。

  • 命令行模式:

    mysql> alter table student
        -> rename to studentChange;
    Query OK, 0 rows affected (0.26 sec)
    
    mysql> show tables;
    +------------------+
    | Tables_in_school |
    +------------------+
    | studentchange    |
    | timetest         |
    | timetest1        |
    | timetest3        |
    | timetest4        |
    | timetset2        |
    +------------------+
    6 rows in set (0.00 sec)
    

    提示:用户可以在修改表名称时使用 DESC 命令查看修改后两个表的结构,修改表名并不修改表的结构,因此修改名称后的表和修改名称前的表的结构是相同的。

  • sqlyog:

    ALTER TABLE studentChange RENAME TO student;
    SHOW TABLES;
    

    结果:
    MySQL_第13张图片

5.3 删除数据表

在 MySQL 数据库中,对于不再需要的数据表,我们可以将其从数据库中删除。

1. 基本语法

当需要删除一个表的时候,可以使用 DROP TABLE 语句来完成,语法格式如下:

DROP TABLE [IF EXISTS] <表名> [ , <表名1> , <表名2>]

语法说明如下:

  • <表名>:被删除的表名。DROP TABLE 语句可以同时删除多个表,用户必须拥有该命令的权限。
  • 表被删除时,所有的表数据和表定义会被取消,所以使用本语句要小心。
  • 表被删除时,用户在该表上的权限并不会自动被删除。
  • 参数IF EXISTS用于在删除前判断删除的表是否存在,加上该参数后,在删除表的时候,如果表不存在,SQL 语句可以顺利执行,但会发出警告(warning)。

2. 删除表

实例:删除数据表 timetest、timetest1、timetest2、timetest3、timetest4;

  • 命令行模式:

    mysql> drop table timetest,timetest2,timetest3,timetest4;
    Query OK, 0 rows affected (0.26 sec)
    
    mysql> show tables;
    +------------------+
    | Tables_in_school |
    +------------------+
    | student          |
    +------------------+
    1 rows in set (0.00 sec)
    

6. MySQL 数据管理

6.1 MySQL 主键

“主键(PRIMARY KEY)”的完整称呼是“主键约束”。

MySQL 主键约束是一个列或者列的组合,其值能唯一地标识表中的每一行。

这样的一列或多列称为表的主键,通过它可以强制表的实体完整性。

1. 选取设置主键约束的字段

主键约束即在表中定义一个主键来唯一确定表中每一行数据的标识符。主键可以是表中的某一列或者多列的组合,其中由多列组合的主键称为复合主键。主键应该遵守下面的规则:

  • 每个表只能定义一个主键。
  • 主键值必须唯一标识表中的每一行,且不能为 NULL,即表中不可能存在两行数据有相同的主键值。这是唯一性原则。
  • 一个列名只能在复合主键列表中出现一次。
  • 复合主键不能包含不必要的多余列。当把复合主键的某一列删除后,如果剩下的列构成的主键仍然满足唯一性原则,那么这个复合主键是不正确的。这是最小化原则。

2. 在创建表时设置主键约束

在 CREATE TABLE 语句中,主键是通过 PRIMARY KEY 关键字来指定的。

在定义列的同时指定主键,语法规则如下:

<字段名> <数据类型> PRIMARY KEY [默认值]

实例:在 school数据库中创建 test01 数据表,其主键为 id:

  • 命令行模式:

    mysql> use school;
    Database changed
    mysql> create table test01
        -> (
        -> id int(10) primary key,
        -> name varchar(20),
        -> sex varchar(3)
        -> );
    Query OK, 0 rows affected (1.50 sec)
    
    mysql> desc test01;
    +-------+-------------+------+-----+---------+-------+
    | Field | Type        | Null | Key | Default | Extra |
    +-------+-------------+------+-----+---------+-------+
    | id    | int(10)     | NO   | PRI | NULL    |       |
    | name  | varchar(20) | YES  |     | NULL    |       |
    | sex   | varchar(3)  | YES  |     | NULL    |       |
    +-------+-------------+------+-----+---------+-------+
    3 rows in set (0.00 sec)
    

在定义完所有列之后,指定主键的语法格式为:

[CONSTRAINT <约束名>] PRIMARY KEY [字段名]
  • sqlyog 演示:

    CREATE TABLE test02
    (
    id INT(10),
    NAME VARCHAR(20),
    sex VARCHAR(3),
    PRIMARY KEY(`id`)
    );
    
    DESC test02
    

    结果:
    MySQL_第14张图片

3. 在修改表时添加主键约束

在修改数据表时添加主键约束的语法规则为:

ALTER TABLE <数据表名> ADD PRIMARY KEY(<列名>);

实例:在 school数据库中创建 test03 数据表,并不设置主键:

mysql> create table test03
    -> (
    -> id int(4),
    -> name varchar(20),
    -> sex varchar(3)
    -> );
Query OK, 0 rows affected (0.93 sec)

mysql> desc test03;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(4)      | YES  |     | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
| sex   | varchar(3)  | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

修改数据表 test03,将字段 id 设置为主键:

mysql> alter table test03 add primary key(id);
Query OK, 0 rows affected (0.94 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc test03;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(4)      | NO   | PRI | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
| sex   | varchar(3)  | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

6.2 MySQL 外键约束

MySQL 外键约束(FOREIGN KEY)用来在两个表的数据之间建立链接,它可以是一列或者多列。一个表可以有一个或多个外键。

外键对应的是参照完整性,一个表的外键可以为空值,若不为空值,则每一个外键的值必须等于另一个表中主键的某个值。

外键是表的一个字段,不是本表的主键,但对应另一个表的主键。定义外键后,不允许删除另一个表中具有关联关系的行。

外键的主要作用是保持数据的一致性、完整性。例如,部门表 tb_dept 的主键是 id,在员工表 tb_emp5 中有一个键 deptId 与这个 id 关联。

  • 主表(父表):对于两个具有关联关系的表而言,相关联字段中主键所在的表就是主表。
  • 从表(子表):对于两个具有关联关系的表而言,相关联字段中外键所在的表就是从表。

1. 选取设置 MySQL外键约束的字段

定义一个外键时,需要遵守下列规则:

  • 父表必须已经存在于数据库中,或者是当前正在创建的表。如果是后一种情况,则父表与子表是同一个表,这样的表称为自参照表,这种结构称为自参照完整性。
  • 必须为父表定义主键。
  • 主键不能包含空值,但允许在外键中出现空值。也就是说,只要外键的每个非空值出现在指定的主键中,这个外键的内容就是正确的。
  • 在父表的表名后面指定列名或列名的组合。这个列或列的组合必须是父表的主键或候选键。
  • 外键中列的数目必须和父表的主键中列的数目相同。
  • 外键中列的数据类型必须和父表主键中对应列的数据类型相同。

2. 在创建表时设置外键约束

在数据表中创建外键使用 FOREIGN KEY 关键字,具体的语法规则如下:

[CONSTRAINT <外键名>] FOREIGN KEY 字段名 [,字段名2,…]
REFERENCES <主表名> 主键列1 [,主键列2,…]

其中:

外键名为定义的外键约束的名称,一个表中不能有相同名称的外键;

字段名表示子表需要添加外健约束的字段列;

主表名即被子表外键所依赖的表的名称;

主键列表示主表中定义的主键列或者列组合。

实例:为了展现表与表之间的外键关系,本例在 school 数据库中创建一个教师表 teacher,表结构如下表所示。

字段名称 数据类型 备注
id INT(ll) 教师编号
name VARCHAR(22) 教师姓名
class VARCHAR(22) 教师班级

创建 teacher 表:

mysql> create table teacher
    -> (
    -> id int(11),
    -> name varchar(22),
    -> class varchar(22),
    -> primary key(id)
    -> );
Query OK, 0 rows affected (0.97 sec)

创建数据表 test_grades,并在表 test_grades 上创建外键约束,让它的键 classId 作为外键关联到表 teacher 的主键 id:

mysql> create table test_grades
    -> (
    -> id int(11),
    -> name varchar(25),
    -> classId int(11),
    -> primary key(id),
    -> foreign key(classId) references teacher(id)
    -> );
Query OK, 0 rows affected (0.41 sec)

mysql> desc test_grades;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id      | int(11)     | NO   | PRI | NULL    |       |
| name    | varchar(25) | YES  |     | NULL    |       |
| classId | int(11)     | YES  | MUL | NULL    |       |
+---------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

以上语句执行成功之后,在表 test_grades 上添加了字段为 classId 的外键约束,其依赖于表 teacher 的主键 id.

提示:关联指的是关系数据库中,相关表之间的联系。它是通过相同的属性或属性组来表示的。子表的外键必须关联父表的主键,且关联字段的数据类型必须匹配,如果类型不一样,则创建子表时会出现错误“ERROR 1005(HY000):Can’t create table’database.tablename’(errno:150)”。

3. 在修改表时添加外键约束

在修改数据表时添加外键约束的语法规则为:

ALTER TABLE <数据表名> ADD CONSTRAINT <索引名>
FOREIGN KEY(<列名>) REFERENCES <主表名> (<列名>);

实例:修改数据表 test_grades1 ,将字段 name 设置为外键,与数据表 teacher 的主键 id 进行关联:

mysql> create table test_grades1
    -> (
    -> id int(11),
    -> name varchar(25),
    -> classId int(11),
    -> primary key(id)
    -> );
Query OK, 0 rows affected (0.75 sec)

mysql> alter table test_grades1
    -> add constraint fk_tb_classId
    -> foreign key(classId)
    -> references teacher(id);
Query OK, 0 rows affected (1.46 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show create table test_grades1\G;
*************************** 1. row ***************************
       Table: test_grades1
Create Table: CREATE TABLE `test_grades1` (
  `id` int(11) NOT NULL,
  `name` varchar(25) DEFAULT NULL,
  `classId` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_tb_classId` (`classId`),
  CONSTRAINT `fk_tb_classId` FOREIGN KEY (`classId`) REFERENCES `teacher` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

4. 删除外键约束

对于数据库中定义的外键,如果不再需要,可以将其删除。外键一旦删除,就会解除主表和从表间的关联关系,MySQL 中删除外键的语法格式如下:

ALTER TABLE <表名> DROP FOREIGN KEY <外键约束名>;

实例:删除数据表 test_grades1 中的外键约束:

mysql> alter table test_grades1
    -> drop foreign key fk_tb_classId;
Query OK, 0 rows affected (0.55 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show create table test_grades1\G;
*************************** 1. row ***************************
       Table: test_grades1
Create Table: CREATE TABLE `test_grades1` (
  `id` int(11) NOT NULL,
  `name` varchar(25) DEFAULT NULL,
  `classId` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_tb_classId` (`classId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

可以看到,test_grades1 中已经不存在 FOREIGN KEY,原有的名称为 fk_tb_classId 的外键约束删除成功。

6.3 MySQL 唯一约束

MySQL 唯一约束(Unique Key)要求该列唯一,允许为空,但只能出现一个空值。唯一约束可以确保一列或者几列不出现重复值。

1. 在创建表时设置唯一的约束

在定义完列之后直接使用 UNIQUE 关键字指定唯一约束,语法规则如下:

<字段名> <数据类型> UNIQUE

实例:创建数据表 test04, 指定 name 唯一;

mysql> create table test04
    -> (
    -> id int(11),
    -> name varchar(20),
    -> sex varchar(3),
    -> primary key(id),
    -> unique key(name)
    -> );
Query OK, 0 rows affected (1.06 sec)

mysql> desc test04;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(20) | YES  | UNI | NULL    |       |
| sex   | varchar(3)  | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.01 sec)

UNIQUE 和 PRIMARY KEY 的区别:

  1. 一个表可以有多个字段声明为 UNIQUE,但只能有一个 PRIMARY KEY 声明;

  2. 声明为 PRIMAY KEY 的列不允许有空值,但是声明为 UNIQUE 的字段允许空值的存在。

2. 修改表时添加唯一的约束

在修改表时添加唯一约束的语法格式为:

ALTER TABLE <数据表名> ADD CONSTRAINT <唯一约束名> UNIQUE(<列名>);

实例:修改数据表 test05 , 指定 name 唯一:

mysql> create table test05
    -> (
    -> id int(11),
    -> name varchar(20),
    -> sex varchar(3),
    -> primary key(id)
    -> );
Query OK, 0 rows affected (0.56 sec)

mysql> alter table test05
    -> add constraint unique_name unique(name);
Query OK, 0 rows affected (0.57 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc test05;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(20) | YES  | UNI | NULL    |       |
| sex   | varchar(3)  | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

3. 删除唯一约束

在 MySQL 中删除唯一约束的语法格式如下:

ALTER TABLE <表名> DROP INDEX <唯一约束名>;

实例:删除数据表 test05 中的唯一约束 unique_name:

mysql> alter table test05
    -> drop index unique_name;
Query OK, 0 rows affected (0.63 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc test05;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
| sex   | varchar(3)  | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

6.4 MySQL 检查约束

MySQL 检查约束(CHECK)可以通过 CREATE TABLE 或 ALTER TABLE 语句实现,根据用户实际的完整性要求来定义。它可以分别对列或表实施 CHECK 约束。

1. 选取设置检查约束的字段

检查约束使用 CHECK 关键字,具体的语法格式如下:

CHECK <表达式>

其中:<表达式>指的就是 SQL 表达式,用于指定需要检查的限定条件。

若将 CHECK 约束子句置于表中某个列的定义之后,则这种约束也称为基于列的 CHECK 约束。

在更新表数据的时候,系统会检查更新后的数据行是否满足 CHECK 约束中的限定条件。MySQL 可以使用简单的表达式来实现 CHECK 约束,也允许使用复杂的表达式作为限定条件,例如在限定条件中加入子查询。

注:若将 CHECK 约束子句置于所有列的定义以及主键约束和外键定义之后,则这种约束也称为基于表的 CHECK 约束。该约束可以同时对表中多个列设置限定条件。

2. 在创建表时设置检查约束

创建表时设置检查约束的语法规则如下:

CHECK(<检查约束>)

实例 : 在 school 数据库中创建 test06 数据表,要求 age字段值大于 0 且小于 100 :

mysql> create table test06
    -> (
    -> id int(11),
    -> name varchar(25),
    -> sex varchar(3),
    -> age int(4),
    -> primary key(id),
    -> check(age >0 and age < 100)
    -> );
Query OK, 0 rows affected (0.53 sec)

3. 在修改表时添加检查约束

修改表时设置检查约束的语法规则如下:

 ALTER TABLE <数据表名> ADD CONSTRAINT <检查约束名> CHECK(<检查约束>)

实例 : 修改 test06 数据表,要求 id 字段值大于 0;

mysql> alter table test06
    -> add constraint check_id
    -> check(id > 0);
Query OK, 0 rows affected (0.43 sec)
Records: 0  Duplicates: 0  Warnings: 0

4. 删除检查约束

修改表时删除检查约束的语法规则如下:

 ALTER TABLE <数据表名> DROP CONSTRAINT <检查约束名>;

6.5 MySQL 默认值

“默认值(Default)”的完整称呼是“默认值约束(Default Constraint)”。MySQL 默认值约束用来指定某列的默认值。

例如女性同学较多,性别就可以默认为“女”。如果插入一条新的记录时没有为这个字段赋值,那么系统会自动为这个字段赋值为“女”。

1. 创建表时设置默认值约束

创建表时可以使用 DEFAULT 关键字设置默认值约束,具体的语法规则如下:

 <字段名> <数据类型> DEFAULT <默认值>;

实例:创建数据表 test07,指定性别默认值为男;

mysql> create table test07
    -> (
    -> id int(11),
    -> name varchar(20),
    -> age int(3),
    -> sex varchar(2) default '男'
    -> );
Query OK, 0 rows affected (0.83 sec)

mysql> desc test07;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | YES  |     | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
| age   | int(3)      | YES  |     | NULL    |       |
| sex   | varchar(2)  | YES  |     ||       |
+-------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

以上语句执行成功之后,表 test07 上的字段 sex 拥有了一个默认值男,新插入的记录如果没有指定性别,则默认都为男。

2. 在修改表时添加默认值约束

修改表时添加默认值约束的语法规则如下:

ALTER TABLE <数据表名>
CHANGE COLUMN <字段名> <数据类型> DEFAULT <默认值>;

实例:修改数据表 test07,将性别的默认值修改为女;

mysql> alter table test07
    -> change column sex
    -> sex varchar(3) default '女';
Query OK, 0 rows affected (0.46 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc test07;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | YES  |     | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
| age   | int(3)      | YES  |     | NULL    |       |
| sex   | varchar(3)  | YES  |     ||       |
+-------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

3. 删除默认值约束

修改表时删除默认值约束的语法规则如下:

ALTER TABLE <数据表名>
CHANGE COLUMN <字段名> <字段名> <数据类型> DEFAULT NULL;

实例:修改数据表 test07,将性别的默认值约束删除;

mysql> alter table test07
    -> change column sex
    -> sex varchar(3) default NULL;
Query OK, 0 rows affected (0.43 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc test07;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | YES  |     | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
| age   | int(3)      | YES  |     | NULL    |       |
| sex   | varchar(3)  | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

6.6 MySQL 非空约束

MySQL 非空约束(NOT NULL)可以通过 CREATE TABLE 或 ALTER TABLE 语句实现。

在表中某个列的定义后加上关键字 NOT NULL 作为限定词,来约束该列的取值不能为空。

非空约束(Not Null Constraint)指字段的值不能为空。

对于使用了非空约束的字段,如果用户在添加数据时没有指定值,数据库系统就会报错。

1. 在创建表时设置非空约束

创建表时可以使用 NOT NULL 关键字设置非空约束,具体的语法规则如下:

<字段名> <数据类型> NOT NULL;

实例:创建数据表 test08,指定姓名不能为空;

mysql> create table test08
    -> (
    -> id int(11),
    -> name varchar(22) not null,
    -> age int(3)
    -> );
Query OK, 0 rows affected (1.12 sec)

mysql> desc test08;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | YES  |     | NULL    |       |
| name  | varchar(22) | NO   |     | NULL    |       |
| age   | int(3)      | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

2. 修改表时添加非空约束

修改表时设置非空约束的语法规则如下:

ALTER TABLE <数据表名>
CHANGE COLUMN <字段名>
<字段名> <数据类型> NOT NULL;

实例:修改数据表 test08,指定年龄不能为空;

mysql> alter table test08
    -> change column age
    -> age int(3) not null;
Query OK, 0 rows affected (1.27 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc test08;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | YES  |     | NULL    |       |
| name  | varchar(22) | NO   |     | NULL    |       |
| age   | int(3)      | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

3. 删除非空约束

修改表时删除非空约束的语法规则如下:

ALTER TABLE <数据表名>
CHANGE COLUMN <字段名> <字段名> <数据类型> NULL;

实例:修改数据表 test08,将年龄的非空约束删除;

mysql> alter table test08
    -> change column age
    -> age int(3) null;
Query OK, 0 rows affected (1.37 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc test08;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | YES  |     | NULL    |       |
| name  | varchar(22) | NO   |     | NULL    |       |
| age   | int(3)      | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

6.7 MySQL 查看表中的约束

在 MySQL 中可以使用 SHOW CREATE TABLE 语句来查看表中的约束。

查看数据表中的约束语法格式如下:

SHOW CREATE TABLE <数据表名>;

实例:创建数据表 test09 并指定 id 为主键约束,name 为唯一约束,deptId 为非空约束和外键约束,然后查看表中的约束,输入SQL语句运行结果如下。

mysql> create table test09
    -> (
    -> id int(10),
    -> name varchar(20) unique,
    -> deptId int(10) not null,
    -> salary float default 0,
    -> check(salary>0),
    -> foreign key(deptId) references test06(id),
    -> primary key(id)
    -> );
Query OK, 0 rows affected (1.04 sec)

mysql> show create table test09 \G
*************************** 1. row ***************************
       Table: test09
Create Table: CREATE TABLE `test09` (
  `id` int(10) NOT NULL,
  `name` varchar(20) DEFAULT NULL,
  `deptId` int(10) NOT NULL,
  `salary` float DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`),
  KEY `deptId` (`deptId`),
  CONSTRAINT `test09_ibfk_1` FOREIGN KEY (`deptId`) REFERENCES `test06` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

6.8 MySQL 查询数据表

MySQL 表单查询是指从一张表的数据中查询所需的数据,主要有查询所有字段、查询指定字段、查询指定记录、查询空值、多条件的查询、对查询结果进行排序等。

1. MySQL SELECT 基本语法

MySQL 从数据表中查询数据的基本语句为 SELECT 语句,基本格式如下:

SELECT
{* | <字段列名>}
[
FROM <1>, <2>[WHERE <表达式>
[GROUP BY <group by definition>
[HAVING <expression> [{<operator> <expression>}…]]
[ORDER BY <order by definition>]
[LIMIT[<offset>,] <row count>]
]

其中,各条子句的含义如下:

  • {*|<字段列名>}包含星号通配符的字段列表,表示查询的字段,其中字段列至少包含一个字段名称,如果要查询多个字段,多个字段之间要用逗号隔开,最后一个字段后不要加逗号。
  • FROM <表 1>,<表 2>…,表 1 和表 2 表示查询数据的来源,可以是单个或多个。
  • WHERE 子句是可选项,如果选择该项,将限定查询行必须满足的查询条件。
  • GROUP BY< 字段 >,该子句告诉 MySQL 如何显示查询出来的数据,并按照指定的字段分组。
  • [ORDER BY< 字段 >],该子句告诉 MySQL 按什么样的顺序显示查询出来的数据,可以进行的排序有升序(ASC)和降序(DESC)。
  • [LIMIT[,]],该子句告诉 MySQL 每次显示查询出来的数据条数。

2. 使用 “ * ” 查询表中的全部内容

在 SELECT 语句中使用星号 “*” 通配符查询所有字段。

SELECT 查询记录最简单的形式是从一个表中检索所有记录,实现的方法是使用星号 “*” 通配符指定查找所有列的名称,语法格式如下:

SELECT * FROM 表名;

实例:从 student 表中检索所有字段的数据;

mysql> use school;
Database changed
mysql> select * from student;
+----+-------+----------+-----+---------------------+----------+-------------+
| id | name  | pwd      | sex | birthday            | address  | email       |
+----+-------+----------+-----+---------------------+----------+-------------+
|  1 | 张三  | 123456   || 2010-07-14 19:56:04 | 北京     | 1234@qq.com |
|  2 | 李四  | 123456   || 2020-01-07 19:56:51 | 陕西西安 | 1234@qq.com |
|  3 | Green | 111111   || 2019-03-13 19:57:18 | 华盛顿   | 1234@qq.com |
|  4 | Jim   | 123456   || 2015-05-15 19:57:52 | 芝加哥   | 1234@qq.com |
|  5 | John  | 123456   || 1981-01-23 19:58:20 | 温哥华   | 1234@qq.com |
|  6 | Tom   | 12312124 || 2011-07-13 19:58:43 | 莫斯科   | 1234@qq.com |
|  7 | 王五  | 123456   || 2000-06-15 19:59:08 | 浙江     | 1234@qq.com |
+----+-------+----------+-----+---------------------+----------+-------------+
7 rows in set (0.00 sec)

由执行结果可知,使用星号 “*” 通配符时,将返回所有列,数据列按照创建表时的顺序显示。

注:

  1. 一般情况下,除非需要使用表中所有的字段数据,否则最好不要使用通配符 “*”。
  2. 使用通配符虽然可以节省输入查询语句的时间,但是获取不需要的列数据通常会降低查询和所使用的应用程序的效率。
  3. 通配符的优势是,当不知道所需列的名称时,可以通过通配符获取它们。

根据前面 SELECT 语句的格式,SELECT 关键字后面的字段名为将要查找的数据,因此可以将表中所有字段的名称跟在 SELECT 关键字后面,如果忘记了字段名称,可以使用 DESC 命令查看表的结构。

有时,由于表的字段可能比较多,不一定能记得所有字段的名称,因此该方法很不方便,不建议使用。

实例:查询 students 表中的所有数据;

mysql> select id, name, pwd, sex, birthday, address, email
    -> from student;
+----+-------+----------+-----+---------------------+----------+-------------+
| id | name  | pwd      | sex | birthday            | address  | email       |
+----+-------+----------+-----+---------------------+----------+-------------+
|  1 | 张三  | 123456   || 2010-07-14 19:56:04 | 北京     | 1234@qq.com |
|  2 | 李四  | 123456   || 2020-01-07 19:56:51 | 陕西西安 | 1234@qq.com |
|  3 | Green | 111111   || 2019-03-13 19:57:18 | 华盛顿   | 1234@qq.com |
|  4 | Jim   | 123456   || 2015-05-15 19:57:52 | 芝加哥   | 1234@qq.com |
|  5 | John  | 123456   || 1981-01-23 19:58:20 | 温哥华   | 1234@qq.com |
|  6 | Tom   | 12312124 || 2011-07-13 19:58:43 | 莫斯科   | 1234@qq.com |
|  7 | 王五  | 123456   || 2000-06-15 19:59:08 | 浙江     | 1234@qq.com |
+----+-------+----------+-----+---------------------+----------+-------------+
7 rows in set (0.00 sec)

注:使用“*”可以返回所有列的数值,但若不需要返回所有列的值,为了提高效率,一般采用 SELECT 字段名列表的形式。

3. 查询表中指定的字段

查询表中的某一个字段的语法格式为:

SELECT < 列名 > FROM < 表名 >;

实例:查询 student 表中 name 列所有学生的姓名;

mysql> select name from student;
+-------+
| name  |
+-------+
| 张三  |
| 李四  |
| Green |
| Jim   |
| John  |
| Tom   |
| 王五  |
+-------+
7 rows in set (0.00 sec)

输出结果显示了 student 表中 name 字段下的所有数据。

使用 SELECT 声明可以获取多个字段下的数据,只需要在关键字 SELECT 后面指定要查找的字段名称,不同字段名称之间用逗号“,”分隔开,最后一个字段后面不需要加逗号,语法格式如下:

SELECT <字段名1>,<字段名2>,,<字段名n> FROM <表名>;

实例:从 student 表中获取 id、name 和 sex 三列;

mysql> select id, name, sex
    -> from student;
+----+-------+-----+
| id | name  | sex |
+----+-------+-----+
|  1 | 张三  ||
|  2 | 李四  ||
|  3 | Green ||
|  4 | Jim   ||
|  5 | John  ||
|  6 | Tom   ||
|  7 | 王五  ||
+----+-------+-----+
7 rows in set (0.00 sec)

输出结果显示了 student 表中 id、name 和 sex 三个字段下的所有数据。

6.9 MySQL 去重

在使用 MySQL SELECT 语句查询数据的时候返回的是所有匹配的行。

例如,查询 student 表中所有 pwd 的执行结果如下所示。

mysql> select pwd from student;
+----------+
| pwd      |
+----------+
| 123456   |
| 123456   |
| 111111   |
| 123456   |
| 123456   |
| 12312124 |
| 123456   |
+----------+
7 rows in set (0.00 sec)

可以看到查询结果返回了 7 条记录,其中有一些重复的 pwd 值,有时出于对数据分析的要求,需要消除重复的记录值。这时候就需要用到 DISTINCT 关键字指示 MySQL 消除重复的记录值,语法格式为:

SELECT DISTINCT <字段名> FROM <表名>;

实例:查询 student 表中 pwd 字段的值,返回 pwd 字段的值且不得重复;

mysql> select distinct pwd from student;
+----------+
| pwd      |
+----------+
| 123456   |
| 111111   |
| 12312124 |
+----------+
3 rows in set (0.00 sec)

由运行结果可以看到,这次查询结果只返回了 3 条记录的 pwd 值,且没有重复的值。

6.10 MySQL 设置别名

1. 表别名

在使用 MySQL 查询时,当表名很长或者执行一些特殊查询的时候,为了方便操作或者需要多次使用相同的表时,可以为表指定别名,用这个别名代替表原来的名称。

为表取别名的基本语法格式为:

<表名> [AS] <别名>

其中各子句的含义如下:

  • <表名>:数据中存储的数据表的名称。 ·
  • <别名>:查询时指定的表的新名称。
  • AS:关键字为可选参数。

实例:为 student 表取别名 stu,输入的 SQL 语句和执行结果如下所示。

mysql> select stu.name, stu.sex from student as stu;
+-------+-----+
| name  | sex |
+-------+-----+
| 张三  ||
| 李四  ||
| Green ||
| Jim   ||
| John  ||
| Tom   ||
| 王五  ||
+-------+-----+
7 rows in set (0.00 sec)

注:在为表取别名时,要保证不能与数据库中的其他表的名称冲突。

2. 列别名

在使用 SELECT 语句显示查询结果时,MySQL 会显示每个 SELECT 后面指定输出的列,在有些情况下,显示的列名称会很长或者名称不够直观,MySQL 可以指定列的别名,替换字段或表达式。

为列取别名的基本语法格式为:

<列名> [AS] <列别名>

其中,各子句的语法含义如下:

  • <列名>:为表中字段定义的名称。
  • <列别名>:字段新的名称。
  • AS:关键字为可选参数。

实例:查询 student 表,为 name 取别名 student_name,为 sex 取别名student_sex,输入的 SQL 语句和执行结果如下所示。

mysql> select name as stu_name,
    -> sex as stu_sex
    -> from student;
+----------+---------+
| stu_name | stu_sex |
+----------+---------+
| 张三     ||
| 李四     ||
| Green    ||
| Jim      ||
| John     ||
| Tom      ||
| 王五     ||
+----------+---------+
7 rows in set (0.00 sec)

注:

  1. 表别名只在执行查询时使用,并不在返回结果中显示;
  2. 列定义别名之后,将返回给客户端显示,显示的结果字段为字段列的别名。

6.11 MySQL 限制查询结果的记录条数

在使用 MySQL SELECT 语句时往往返回的是所有匹配的行,有些时候我们仅需要返回第一行或者前几行,这时候就需要用到 MySQL LIMIT 子句。

基本的语法格式如下:

 <LIMIT> [<位置偏移量>,] <行数>

LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。

第一个参数“位置偏移量”指示 MySQL 从哪一行开始显示,是一个可选参数,如果不指定“位置偏移量”,将会从表中的第一条记录开始(第一条记录的位置偏移量是 0,第二条记录的位置偏移量是 1,以此类推);第二个参数“行数”指示返回的记录条数。

实例 :显示 student 表查询结果的前 4 行,输入的 SQL 语句和执行结果如下所示。

mysql> select * from student limit 4;
+----+-------+--------+-----+---------------------+----------+-------------+
| id | name  | pwd    | sex | birthday            | address  | email       |
+----+-------+--------+-----+---------------------+----------+-------------+
|  1 | 张三  | 123456 || 2010-07-14 19:56:04 | 北京     | 1234@qq.com |
|  2 | 李四  | 123456 || 2020-01-07 19:56:51 | 陕西西安 | 1234@qq.com |
|  3 | Green | 111111 || 2019-03-13 19:57:18 | 华盛顿   | 1234@qq.com |
|  4 | Jim   | 123456 || 2015-05-15 19:57:52 | 芝加哥   | 1234@qq.com |
+----+-------+--------+-----+---------------------+----------+-------------+
4 rows in set (0.00 sec)

由结果可以看到,该语句没有指定返回记录的“位置偏移量”参数,显示结果从第一行开始,“行数”参数为 4,因此返回的结果为表中的前 4 行记录。

若指定返回记录的开始位置,则返回结果为从“位置偏移量”参数开始的指定行数,“行数”参数指定返回的记录条数。

实例:在 student 表中,使用 LIMIT 子句返回从第 4 条记录开始的行数为 4 的记录,输入的 SQL 语句和执行结果如下所示。

mysql> select * from student limit 3, 4;
+----+------+----------+-----+---------------------+---------+-------------+
| id | name | pwd      | sex | birthday            | address | email       |
+----+------+----------+-----+---------------------+---------+-------------+
|  4 | Jim  | 123456   || 2015-05-15 19:57:52 | 芝加哥  | 1234@qq.com |
|  5 | John | 123456   || 1981-01-23 19:58:20 | 温哥华  | 1234@qq.com |
|  6 | Tom  | 12312124 || 2011-07-13 19:58:43 | 莫斯科  | 1234@qq.com |
|  7 | 王五 | 123456   || 2000-06-15 19:59:08 | 浙江    | 1234@qq.com |
+----+------+----------+-----+---------------------+---------+-------------+
4 rows in set (0.00 sec)

由结果可以看到,该语句指示 MySQL 返回从第 4 条记录行开始的之后的 4 条记录,第一个数字“3”表示从第 4 行开始(位置偏移量从 0 开始,第 4 行的位置偏移量为 3),第二个数字 4 表示返回的行数。

所以,带一个参数的 LIMIT 指定从查询结果的首行开始,唯一的参数表示返回的行数,即“LIMIT n”与“LIMIT 0,n”等价。带两个参数的 LIMIT 可返回从任何位置开始的指定行数的数据。

返回第一行时,位置偏移量是 0。因此,“LIMIT 1,1”返回第 2 行,而不是第 1 行。

注意:MySQL 5.7 中可以使用“LIMIT 4 OFFSET 3”,意思是获取从第5条记录开始的后面的3条记录,和“LIMIT 4,3”返回的结果相同。

6.12 MySQL 对查询结果进行排序

在 MySQL SELECT 语句中,ORDER BY 子句主要用来将结果集中的数据按照一定的顺序进行排序。

其语法格式为:

 ORDER BY {<列名> | <表达式> | <位置>} [ASC|DESC]

语法说明如下。

  • 列名:指定用于排序的列。可以指定多个列,列名之间用逗号分隔。

  • 表达式:指定用于排序的表达式。

  • 位置:指定用于排序的列在 SELECT 语句结果集中的位置,通常是一个正整数。

  • ASC|DESC:关键字 ASC 表示按升序分组,关键字 DESC 表示按降序分组,其中 ASC 为默认值。这两个关键字必须位于对应的列名、表达式、列的位置之后。

使用 ORDER BY 子句应该注意以下几个方面:

  • ORDER BY 子句中可以包含子查询。
  • 当排序的值中存在空值时,ORDER BY 子句会将该空值作为最小值来对待。
  • 当在 ORDER BY 子句中指定多个列进行排序时,MySQL 会按照列的顺序从左到右依次进行排序。
  • 查询的数据并没有以一种特定的顺序显示,如果没有对它们进行排序,则将根据插入到数据表中的顺序显示。使用 ORDER BY 子句对指定的列数据进行排序。

实例:查询 student 表的 age 字段值,并对其进行排序,输入的 SQL 语句和执行结果如下所示。

mysql> select * from student order by age;
+----+-------+----------+-----+------+---------------------+----------+-------------+
| id | name  | pwd      | sex | age  | birthday            | address  | email       |
+----+-------+----------+-----+------+---------------------+----------+-------------+
|  2 | 李四  | 123456   ||    0 | 2020-01-07 19:56:51 | 陕西西安 | 1234@qq.com |
|  3 | Green | 111111   ||    1 | 2019-03-13 19:57:18 | 华盛顿   | 1234@qq.com |
|  4 | Jim   | 123456   ||    5 | 2015-05-15 19:57:52 | 芝加哥   | 1234@qq.com |
|  6 | Tom   | 12312124 ||    9 | 2011-07-13 19:58:43 | 莫斯科   | 1234@qq.com |
|  1 | 张三  | 123456   ||   10 | 2010-07-14 19:56:04 | 北京     | 1234@qq.com |
|  7 | 王五  | 123456   ||   20 | 2000-06-15 19:59:08 | 浙江     | 1234@qq.com |
|  5 | John  | 123456   ||   39 | 1981-01-23 19:58:20 | 温哥华   | 1234@qq.com |
+----+-------+----------+-----+------+---------------------+----------+-------------+
7 rows in set (0.00 sec)

该语句通过指定 ORDER BY 子句,MySQL 对查询的 age 列的数据按数值的大小进行了升序排序。

有时需要根据多列进行排序。对多列数据进行排序要将需要排序的列之间用逗号隔开。

实例:查询 student 表中的 name 和 age 字段,先按 age 排序,再按 name 排序,输入的 SQL 语句和执行结果如下所示。

mysql> select name, age
    -> from student
    -> order by age, name;
+-------+------+
| name  | age  |
+-------+------+
| 李四  |    0 |
| Green |    1 |
| Jim   |    5 |
| Tom   |    9 |
| 张三  |   10 |
| 王五  |   20 |
| John  |   39 |
+-------+------+
7 rows in set (0.00 sec)

注:在对多列进行排序时,首行排序的第一列必须有相同的列值,才会对第二列进行排序。如果第一列数据中所有的值都是唯一的,将不再对第二列进行排序。

默认情况下,查询数据按字母升序进行排序(A~Z),但数据的排序并不仅限于此,还可以使用 ORDER BY 对查询结果进行降序排序(Z~A),这可以通过关键字 DESC 实现。可以对多列进行不同的顺序排序。

实例:查询 student 表,先按 age 降序排序,再按 name 升序排序,输入的 SQL 语句和执行过程如下所示。

mysql> select name, age
    -> from student
    -> order by age desc, name asc;
+-------+------+
| name  | age  |
+-------+------+
| John  |   39 |
| 王五  |   20 |
| 张三  |   10 |
| Tom   |    9 |
| Jim   |    5 |
| Green |    1 |
| 李四  |    0 |
+-------+------+
7 rows in set (0.00 sec)

注:DESC 关键字只对前面的列进行降序排列,在这里只对 age 排序,而并没有对 name 进行排序,因此,age 按降序排序,而 name 仍按升序排序,如果要对多列进行降序排序,必须要在每一列的后面加 DESC 关键字。

6.13 MySQL 条件查询

在使用 MySQL SELECT语句时,可以使用 WHERE 子句来指定查询条件,从 FROM 子句的中间结果中选取适当的数据行,达到数据过滤的效果。

语法格式如下:

 WHERE <查询条件> {<判定运算1><判定运算2>,…}

其中,判定运算其结果取值为 TRUEFALSEUNKNOWN

判定运算的语法分类如下:

  • <表达式1>{=|<|<=|>|>=|<=>|<>|!=}<表达式2>
  • <表达式1>[NOT]LIKE<表达式2>
  • <表达式1>[NOT][REGEXP|RLIKE]<表达式2>
  • <表达式1>[NOT]BETWEEN<表达式2>AND<表达式3>
  • <表达式1>IS[NOT]NULL

1. 单一条件的查询语句

实例:在表 student 中查询年龄为 20 的学生的姓名,输入的 SQL 语句和行结果如下所示。

mysql> select name, age
    -> from student
    -> where age = 20;
+------+------+
| name | age  |
+------+------+
| 王五 |   20 |
+------+------+
1 row in set (0.00 sec)

该语句采用了简单的相等过滤,查询一个指定列 age 的具体值 20。

实例:查询年龄小于 20 的学生的姓名,输入的 SQL 语句和执行结果如下所示。

mysql> select name,age
    -> from student
    -> where age < 20;
+-------+------+
| name  | age  |
+-------+------+
| 张三  |   10 |
| 李四  |    0 |
| Green |    1 |
| Jim   |    5 |
| Tom   |    9 |
+-------+------+
5 rows in set (0.00 sec)

可以看到,查询结果中所有记录的 age 字段的值均小于 20 岁,而大于或等于 20 岁的记录没有被返回。

2. 多条件的查询语句

使用 SELECT 查询时,可以增加查询的限制条件,这样可以使查询的结果更加精确。

MySQL 在 WHERE 子句中使用 AND 操作符限定只有满足所有查询条件的记录才会被返回。

可以使用 AND 连接两个甚至多个查询条件,多个条件表达式之间用 AND 分开。

实例:在 student 表中查询 age 大于 20,并且 id 小于等于 5 的学生的信息,输入的 SQL 语句和执行结果如下所示。

mysql> select * from student
    -> where age > 20 and id <= 5;
+----+------+--------+-----+------+---------------------+---------+-------------+
| id | name | pwd    | sex | age  | birthday            | address | email       |
+----+------+--------+-----+------+---------------------+---------+-------------+
|  5 | John | 123456 ||   39 | 1981-01-23 19:58:20 | 温哥华  | 1234@qq.com |
+----+------+--------+-----+------+---------------------+---------+-------------+
1 row in set (0.00 sec)

注:上例的 WHERE 子句中只包含一个 AND 语句,把两个过滤条件组合在一起,实际上可以添加多个 AND 过滤条件,增加条件的同时增加一个 AND 关键字。

3. 使用 LIKE 的模糊查询

字符串匹配的语法格式如下:

 <表达式1> [NOT] LIKE <表达式2>

字符串匹配是一种模式匹配,使用运算符 LIKE 设置过滤条件,过滤条件使用通配符进行匹配运算,而不是判断是否相等进行比较。

相互间进行匹配运算的对象可以是 CHAR、VARCHAR、TEXT、DATETIME 等数据类型。运算返回的结果是 TRUE 或 FALSE。

利用通配符可以在不完全确定比较值的情形下创建一个比较特定数据的搜索模式,并置于关键字 LIKE 之后。可以在搜索模式的任意位置使用通配符,并且可以使用多个通配符。MySQL 支持的通配符有以下两种:

1) 百分号(%)

百分号是 MySQL 中常用的一种通配符,在过滤条件中,百分号可以表示任何字符串,并且该字符串可以出现任意次。

使用百分号通配符要注意以下几点:

  • MySQL 默认是不区分大小写的,若要区分大小写,则需要更换字符集的校对规则。
  • 百分号不匹配空值。
  • 百分号可以代表搜索模式中给定位置的 0 个、1 个或多个字符。
  • 尾空格可能会干扰通配符的匹配,一般可以在搜索模式的最后附加一个百分号。

2) 下划线(_)

下划线通配符和百分号通配符的用途一样,下画线只匹配单个字符,而不是多个字符,也不是 0 个字符。

注意:不要过度使用通配符,对通配符检索的处理一般会比其他检索方式花费更长的时间。

实例:在 student 表中,查找所有以 “J” 字母开头的学生姓名,输入的 SQL 的语句和执行结果如下所示。

mysql> select name from student
    -> where name like 'J%';
+------+
| name |
+------+
| Jim  |
| John |
+------+
2 rows in set (0.00 sec)

注:在搜索匹配时,通配符“%”可以放在不同位置。

实例:在 student 表中,查找所有包含 “m” 字母的学生姓名,输入的 SQL 的语句和执行结果如下所示。

mysql> select * from student
    -> where name like '%m';
+----+------+----------+-----+------+---------------------+---------+-------------+
| id | name | pwd      | sex | age  | birthday            | address | email       |
+----+------+----------+-----+------+---------------------+---------+-------------+
|  4 | Jim  | 123456   ||    5 | 2015-05-15 19:57:52 | 芝加哥  | 1234@qq.com |
|  6 | Tom  | 12312124 ||    9 | 2011-07-13 19:58:43 | 莫斯科  | 1234@qq.com |
+----+------+----------+-----+------+---------------------+---------+-------------+
2 rows in set (0.00 sec)

由执行结果可以看出,该语句查询字符串中包含字母 m 的学生的姓名,只要名字中有字母 m,其前面或后面无论有多少个字符,都满足查询的条件。

实例:在 student 表中,查找所有以字母 “n” 结尾,且 “n” 前面只有 4 个字母的学生的姓名,输入的 SQL 语句和执行结果如下所示。

mysql> select * from student
    -> where name like '____n';
+----+-------+--------+-----+------+---------------------+---------+-------------+
| id | name  | pwd    | sex | age  | birthday            | address | email       |
+----+-------+--------+-----+------+---------------------+---------+-------------+
|  3 | Green | 111111 ||    1 | 2019-03-13 19:57:18 | 华盛顿  | 1234@qq.com |
+----+-------+--------+-----+------+---------------------+---------+-------------+
1 row in set (0.00 sec)

4. 日期字段作为条件的查询语句

以日期字段作为条件,可以使用比较运算符设置查询条件,也可以使用 BETWEEN AND 运算符查询某个范围内的值。

BETWEEN AND 用来查询某个范围内的值,该操作符需要两个参数,即范围的开始值和结束值,若字段值满足指定的范围查询条件,则这些记录被返回。

实例:在表 student 中查询 birthday 在 2016-01-01 之前的学生的信息,输入的 SQL 语句和执行结果如下所示。

mysql> select * from student
    -> where birthday < '2016-01-01';
+----+------+----------+-----+------+---------------------+---------+-------------+
| id | name | pwd      | sex | age  | birthday            | address | email       |
+----+------+----------+-----+------+---------------------+---------+-------------+
|  1 | 张三 | 123456   ||   10 | 2010-07-14 19:56:04 | 北京    | 1234@qq.com |
|  4 | Jim  | 123456   ||    5 | 2015-05-15 19:57:52 | 芝加哥  | 1234@qq.com |
|  5 | John | 123456   ||   39 | 1981-01-23 19:58:20 | 温哥华  | 1234@qq.com |
|  6 | Tom  | 12312124 ||    9 | 2011-07-13 19:58:43 | 莫斯科  | 1234@qq.com |
|  7 | 王五 | 123456   ||   20 | 2000-06-15 19:59:08 | 浙江    | 1234@qq.com |
+----+------+----------+-----+------+---------------------+---------+-------------+
5 rows in set (0.00 sec)

实例:在表 student 中查询注册日期在 2010-01-01 和 2016-01-01 之间的学生的信息,输入的 SQL 语句和执行结果如下所示。

mysql> select * from student
    -> where birthday between '2010-01-01' and '2016-01-01';
+----+------+----------+-----+------+---------------------+---------+-------------+
| id | name | pwd      | sex | age  | birthday            | address | email       |
+----+------+----------+-----+------+---------------------+---------+-------------+
|  1 | 张三 | 123456   ||   10 | 2010-07-14 19:56:04 | 北京    | 1234@qq.com |
|  4 | Jim  | 123456   ||    5 | 2015-05-15 19:57:52 | 芝加哥  | 1234@qq.com |
|  6 | Tom  | 12312124 ||    9 | 2011-07-13 19:58:43 | 莫斯科  | 1234@qq.com |
+----+------+----------+-----+------+---------------------+---------+-------------+
3 rows in set (0.00 sec)

6.14 MySQL 常用运算符

MySQL 数据库中的表结构确立后,表中的数据代表的意义就已经确定。而通过 MySQL 运算符进行运算,就可以获取到表结构以外的另一种数据。

例如,学生表中存在一个 birth 字段,这个字段表示学生的出生年份。而运用 MySQL 的算术运算符用当前的年份减学生出生的年份,那么得到的就是这个学生的实际年龄数据。

MySQL 支持 4 种运算符,分别是:

  • 算术运算符,例如:加、减、乘、除等。

  • 比较运算符:包括大于、小于、等于或者不等于,等等。主要用于数值的比较、字符串的匹配等方面。例如:LIKE、IN、BETWEEN AND 和 IS NULL 等都是比较运算符,还包括正则表达式的 REGEXP 也是比较运算符。

  • 逻辑运算符:包括与、或、非和异或等逻辑运算符。其返回值为布尔型,真值(1 或 true)和假值(0 或 false)。

  • 位运算符:包括按位与、按位或、按位取反、按位异或、按位左移和按位右移等位运算符。位运算必须先将数据转换为二进制,然后在二进制格式下进行操作,运算完成后,将二进制的值转换为原来的类型,返回给用户。

1. 算术运算符

算术运算符是 SQL 中最基本的运算符,MySQL 中的算术运算符如下表所示。

算术运算符 说明
+ 加法运算
- 减法运算
* 乘法运算
/ 除法运算,返回商
% 求余运算,返回余数

2. 比较运算符

比较运算符的语法格式为:

<表达式1> {= | < | <= | > | >= | <=> | < > | !=} <表达式2>

MySQL 支持的比较运算符如下表所示。

比较运算符 说明
= 等于
< 小于
<= 小于等于
> 大于
>= 大于等于
<=> 安全的等于,不会返回 UNKNOWN
<> 或!= 不等于
IS NULL 或 ISNULL 判断一个值是否为 NULL
IS NOT NULL 判断一个值是否不为 NULL
LEAST 当有两个或多个参数时,返回最小值
GREATEST 当有两个或多个参数时,返回最大值
BETWEEN AND 判断一个值是否落在两个值之间
IN 判断一个值是IN列表中的任意一个值
NOT IN 判断一个值不是IN列表中的任意一个值
LIKE 通配符匹配
REGEXP 正则表达式匹配

下面分别介绍不同的比较运算符的使用方法。

1) 等于运算符“=”

等号“=”用来判断数字、字符串和表达式是否相等。如果相等,返回值为 1,否则返回值为 0。

数据进行比较时,有如下规则:

  • 若有一个或两个参数为 NULL,则比较运算的结果为 NULL。
  • 若同一个比较运算中的两个参数都是字符串,则按照字符串进行比较。
  • 若两个参数均为正数,则按照整数进行比较。
  • 若一个字符串和数字进行相等判断,则 MySQL 可以自动将字符串转换成数字。

2) 安全等于运算符“<=>”

用于比较两个表达式的值。当两个表达式的值中有一个为空值或者都为空值时,将返回 UNKNOWN。

对于运算符“<=>”,当两个表达式彼此相等或都等于空值时,比较结果为 TRUE;若其中一个是空值或者都是非空值但不相等时,则为 FALSE,不会出现 UNKNOWN 的情况。

3) 不等于运算符“<>”或者“!=”

“<>”或者“!=”用于数字、字符串、表达式不相等的判断。如果不相等,返回值为 1;否则返回值为 0。这两个运算符不能用于判断空值(NULL)。

4) 小于或等于运算符“<=”

“<=”用来判断左边的操作数是否小于或等于右边的操作数。如果小于或等于,返回值为 1;否则返回值为 0。“<=”不能用于判断空值。

5) 小于运算符“<”

“<”用来判断左边的操作数是否小于右边的操作数。如果小于,返回值为 1;否则返回值为 0。“<”不能用于判断空值。

6) 大于或等于运算符“>=”

“>=”用来判断左边的操作数是否大于或等于右边的操作数。如果大于或等于,返回值为 1;否则返回值为 0。“>=”不能用于判断空值。

7) 大于运算符“>”

“>”用来判断左边的操作数是否大于右边的操作数。如果大于,返回值为 1;否则返回值为 0。“>”不能用于判断空值。

8) IS NULL(或者 ISNULL)

IS NULL 和 ISNULL 用于检验一个值是否为 NULL,如果为 NULL,返回值为 1;否则返回值为 0。

9) IS NOT NULL

IS NOT NULL 用于检验一个值是否为非 NULL,如果为非 NULL,返回值为 1;否则返回值为 0。

10) BETWWEN AND

语法格式为:

<表达式> BETWEEN <最小值> AND <最大值>

<表达式>大于或等于<最小值>,且小于或等于<最大值>,则 BETWEEN 的返回值为 1;否则返回值为 0。

11) LEAST

语法格式为:

LEAST(<1>,<2>,,<值n>)

其中,值 n 表示参数列表中有 n 个值。存在两个或多个参数的情况下,返回最小值。若任意一个自变量为 NULL,则 LEAST() 的返回值为 NULL。

12) GREATEST

语法格式为:

GREATEST (<1>,<2>,,<值n>)

其中,值 n 表示参数列表中有 n 个值。存在两个或多个参数的情况下,返回最大值。若任意一个自变量为 NULL,则 GREATEST() 的返回值为 NULL。

13) IN

IN 运算符用来判断操作数是否为 IN 列表中的一个值。如果是,返回值为 1;否则返回值为 0。

14) NOT IN

NOT IN 运算符用来判断表达式是否为 IN 列表中的一个值。如果不是,返回值为 1;否则返回值为 0。

3. 逻辑运算符

在 SQL 语言中,所有逻辑运算符求值所得的结果均为 TRUE、FALSE 或 NULL。在 MySQL 中分别体现为 1(TRUE)、0(FALSE)和 NULL。

MySQL 中的逻辑运算符如下表所示。

逻辑运算符 说明
NOT 或者 ! 逻辑非
AND 或者 && 逻辑与
OR 或者 || 逻辑或
XOR 逻辑异或

下面分别介绍不同的逻辑运算符的使用方法。

1) NOT 或者 !

逻辑非运算符 NOT 或者 !,表示当操作数为 0 时,返回值为 1;当操作数为非零值时,返回值为 0;当操作数为 NULL 时,返回值为 NULL。

2) AND 或者 &&

逻辑与运算符 AND 或者 &&,表示当所有操作数均为非零值并且不为 NULL 时,返回值为 1;当一个或多个操作数为 0 时,返回值为 0;其余情况返回值为 NULL。

3) OR 或者 ||

逻辑或运算符 OR 或者 ||,表示当两个操作数均为非 NULL 值且任意一个操作数为非零值时,结果为 1,否则结果为 0;当有一个操作数为 NULL 且另一个操作数为非零值时,结果为 1,否则结果为 NULL;当两个操作数均为 NULL 时,所得结果为 NULL。

4) XOR

逻辑异或运算符 XOR。当任意一个操作数为 NULL 时,返回值为 NULL;对于非 NULL 的操作数,若两个操作数都不是 0 或者都是 0 值,则返回结果为 0;若一个为 0,另一个不为非 0,则返回结果为 1。

4. 位运算符

位运算符是用来对二进制字节中的位进行移位或者测试处理的。

MySQL 中提供的位运算符如下表所示。

位运算符 说明
| 按位或
& 按位与
^ 按位异或
<< 按位左移
>> 按位右移
~ 按位取反,反转所有比特

下面分别介绍不同的位运算符的使用方法。

1) 位或运算符“|”

位或运算的实质是将参与运算的两个数据按对应的二进制数逐位进行逻辑或运算。若对应的二进制位有一个或两个为 1,则该位的运算结果为 1,否则为 0。

2) 位与运算符“&”

位与运算的实质是将参与运算的两个数据按对应的二进制数逐位进行逻辑与运算。若对应的二进制位都为 1,则该位的运算结果为 1,否则为 0。

3) 位异或运算符“^”

位异或运算的实质是将参与运算的两个数据按对应的二进制数逐位进行逻辑异或运算。对应的二进制位不同时,对应位的结果才为 1。如果两个对应位都为 0 或者都为 1,则对应位的结果为 0。

4) 位左移运算符“<<”

位左移运算符“<<”使指定的二进制值的所有位都左移指定的位数。左移指定位数之后,左边高位的数值将被移出并丢弃,右边低位空出的位置用 0 补齐。

语法格式为 表达式 << n,这里 n 指定值要移位的位数。

5) 位右移运算符“>>”

位右移运算符“>>”使指定的二进制值的所有位都右移指定的位数。右移指定位数之后,右边高位的数值将被移出并丢弃,左边低位空出的位置用 0 补齐。

语法格式为表达式 >> n,这里 n 指定值要移位的位数。

6) 位取反运算符“~”

位取反运算符的实质是将参与运算的数据按对应的二进制数逐位反转,即 1 取反后变 0,0 取反后变为 1。

注:在无法确定优先级的情况下,可以使用圆括号“()”来改变优先级,并且这样会使计算过程更加清晰。

6.15 MySQL 内连接查询

内连接是通过在查询中设置连接条件的方式,来移除查询结果集中某些数据行后的交叉连接。简单来说,就是利用条件表达式来消除交叉连接的某些数据行。

在 MySQL FROM 子句中使用关键字 INNER JOIN 连接两张表,并使用 ON 子句来设置连接条件。如果没有任何条件,INNER JOINCROSS JOIN 在语法上是等同的,两者可以互换。

语法格式如下:

SELECT <列名1,列名2>
FROM <表名1> INNER JOIN <表名2> [ ON子句]

语法说明如下。

  • <列名1,列名2…>:需要检索的列名。
  • <表名1><表名2>:进行内连接的两张表的表名。

内连接是系统默认的表连接,所以在 FROM 子句后可以省略 INNER 关键字,只用关键字 JOIN。使用内连接后,FROM 子句中的 ON 子句可用来设置连接表的条件。

在 FROM 子句中可以在多个表之间连续使用 INNER JOINJOIN,如此可以同时实现多个表的内连接。

实例:表 student 和表 teacher 都包含相同数据类型的字段 id,在两个表之间使用内连接查询。输入的 SQL 语句和执行结果如下所示。

mysql> select student.id, student.name, age, sex ,class
    -> from student, teacher
    -> where student.id = teacher.id;
+----+------+------+-----+-------+
| id | name | age  | sex | class |
+----+------+------+-----+-------+
|  1 | 张三 |   10 || 一班  |
|  2 | 李四 |    0 || 二班  |
+----+------+------+-----+-------+
2 rows in set (0.00 sec)

在这里,SELECT 语句与前面介绍的最大差别是:SELECT 后面指定的列分别属于两个不同的表,id、name、age 、sex 在表 student 中,而 class 在表 teacher 中,同时 FROM 字句列出了两个表 student 和 teacher。WHERE 子句在这里作为过滤条件,指明只有两个表中的 id 字段值相等的时候才符合连接查询的条件。

返回的结果可以看到,显示的记录是由两个表中的不同列值组成的新记录。

提示:因为 student 表和 teacher 表中有相同的字段 id,所以在比较的时候,需要完全限定表名(格式为“表名.列名”),如果只给出 id,MySQL 将不知道指的是哪一个,并返回错误信息。

实例:在 student 表和 teacher 表之间,使用 INNER JOIN 语法进行内连接查询,输入的 SQL 语句和执行结果如下所示。

mysql> select student.id, student.name, age, sex ,class
    -> from student inner join teacher
    -> where student.id = teacher.id;
+----+------+------+-----+-------+
| id | name | age  | sex | class |
+----+------+------+-----+-------+
|  1 | 张三 |   10 || 一班  |
|  2 | 李四 |    0 || 二班  |
+----+------+------+-----+-------+
2 rows in set (0.00 sec)

在这里的查询语句中,两个表之间的关系通过 INNER JOIN 指定。使用这种语法的时候,连接的条件使用 ON 子句给出,而不是 WHERE,ON 和 WHERE 后面指定的条件相同。

提示:使用 WHERE 子句定义连接条件比较简单明了,而 INNER JOIN 语法是 ANSI SQL 的标准规范,使用 INNER JOIN 连接语法能够确保不会忘记连接条件,而且 WHERE 子句在某些时候会影响查询的性能。

6.16 MySQL 外连接查询

MySQL 中内连接是在交叉连接的结果集上返回满足条件的记录;而外连接先将连接的表分为基表和参考表,再以基表为依据返回满足和不满足条件的记录。

外连接更加注重两张表之间的关系

按照连接表的顺序,可以分为左外连接和右外连接。

  • 左外连接又称为左连接,在 FROM 子句中使用关键字 LEFT OUTER JOIN 或者 LEFT JOIN,用于接收该关键字左表(基表)的所有行,并用这些行与该关键字右表(参考表)中的行进行匹配,即匹配左表中的每一行及右表中符合条件的行。

    在左外连接的结果集中,除了匹配的行之外,还包括左表中有但在右表中不匹配的行,对于这样的行,从右表中选择的列的值被设置为 NULL,即左外连接的结果集中的 NULL 值表示右表中没有找到与左表相符的记录。

    实例:在 student 表和 teacher 表中查询所有学生,包括没有班级的学生,输入的 SQL 语句和执行结果如下所示。

    mysql> select student.name, class
        -> from student left join teacher
        -> on student.id = teacher.id;
    +--------+-------+
    | name   | class |
    +--------+-------+
    | 张三   | 一班  |
    | 李四   | 二班  |
    | Green  | NULL  |
    | Jim    | NULL  |
    | John   | NULL  |
    | Tom    | NULL  |
    | 王五   | NULL  |
    | 零零七 | NULL  |
    +--------+-------+
    8 rows in set (0.00 sec)
    

    结果显示了 8 条记录,name 为 Green 等的学生目前没有班级,因为对应的 teacher 表中并没有该学生的班级信息,所以该条记录只取出了 student 表中相应的值,而从 teacher 表中取出的值为 NULL。

  • 右外连接又称为右连接,在 FROM 子句中使用 RIGHT OUTER JOIN 或者 RIGHT JOIN。与左外连接相反,右外连接以右表为基表,连接方法和左外连接相同。在右外连接的结果集中,除了匹配的行外,还包括右表中有但在左表中不匹配的行,对于这样的行,从左表中选择的值被设置为 NULL。

    实例:在 student 表和 teacher 表中查询所有班级,包括没有学生的班级,输入的 SQL 语句和执行结果如下所示。

    mysql> select student.name, class
        -> from student right join teacher
        -> on student.id = teacher.id;
    +------+-------+
    | name | class |
    +------+-------+
    | 张三 | 一班  |
    | 李四 | 二班  |
    +------+-------+
    2 rows in set (0.00 sec)
    

6.17 MySQL 子查询

子查询指一个查询语句嵌套在另一个查询语句内部的查询,这个特性从 MySQL4.1 开始引入,在 SELECT 子句中先计算子查询,子查询结果作为外层另一个查询的过滤条件,查询可以基于一个表或者多个表。

子查询中常用的操作符有 ANY(SOME)、ALL、IN 和 EXISTS。

子查询可以添加到 SELECT、UPDATE 和 DELETE 语句中,而且可以进行多层嵌套。子查询也可以使用比较运算符,如“<”、“<=”、“>”、“>=”、“!=”等。

1. 子查询中常用的运算符

1). IN 子查询

结合关键字 IN 所使用的子查询主要用于判断一个给定值是否存在于子查询的结果集中。其语法格式为:

<表达式> [NOT] IN <子查询>

语法说明如下。

  • <表达式>:用于指定表达式。当表达式与子查询返回的结果集中的某个值相等时,返回 TRUE,否则返回 FALSE;若使用关键字 NOT,则返回的值正好相反。
  • <子查询>:用于指定子查询。这里的子查询只能返回一列数据。对于比较复杂的查询要求,可以使用 SELECT 语句实现子查询的多层嵌套。

2). 比较运算符子查询

比较运算符所使用的子查询主要用于对表达式的值和子查询返回的值进行比较运算。其语法格式为:

<表达式> {= | < | > | >= | <= | <=> | < > | != }
{ ALL | SOME | ANY} <子查询>

语法说明如下:

  • <子查询>:用于指定子查询。
  • <表达式>:用于指定要进行比较的表达式。
  • ALLSOMEANY:可选项。用于指定对比较运算的限制。其中,关键字 ALL 用于指定表达式需要与子查询结果集中的每个值都进行比较,当表达式与每个值都满足比较关系时,会返回 TRUE,否则返回 FALSE;关键字 SOME 和 ANY 是同义词,表示表达式只要与子查询结果集中的某个值满足比较关系,就返回 TRUE,否则返回 FALSE。

3). EXIST 子查询

关键字 EXIST 所使用的子查询主要用于判断子查询的结果集是否为空。其语法格式为:

EXIST <子查询>

若子查询的结果集不为空,则返回 TRUE;否则返回 FALSE。

2. 子查询的应用

实例:在 student 表中查询 sex 为 男 的学生 id,并根据学生 id 查询该学生的名字,输入的 SQL 语句和执行结果如下所示。

mysql> select name from student
    -> where id in
    -> (select id
    -> from student
    -> where sex = '男');
+------+
| name |
+------+
| 李四 |
| Jim  |
| John |
| Tom  |
| 王五 |
+------+
5 rows in set (0.00 sec)

上述查询过程可以分步执行,首先内层子查询查出 student 表中符合条件的学生 ID,单独执行内查询,查询结果如下所示。

mysql> select id
    -> from student
    -> where sex = '男';
+----+
| id |
+----+
|  2 |
|  4 |
|  5 |
|  6 |
|  7 |
+----+
5 rows in set (0.00 sec)

可以看到,符合条件的 id 列的值有五个:2、4、5、6、7。然后执行外层查询,在 student 表中查询 id 等于 2、4、5、6、7 的学生的名字。嵌套子查询语句还可以写为如下形式,可以实现相同的效果。

mysql> select name
    -> from student
    -> where id in(2,4,5,6,7);
+------+
| name |
+------+
| 李四 |
| Jim  |
| John |
| Tom  |
| 王五 |
+------+
5 rows in set (0.00 sec)

上例说明在处理 SELECT 语句时,MySQL 实际上执行了两个操作过程,即先执行内层子查询,再执行外层查询,内层子查询的结果作为外部查询的比较条件。

实例:与前一个例子类似,但是在 SELECT 语句中使用 NOT IN 关键字,输入的 SQL 语句和执行结果如下所示。

mysql> select name from student
    -> where id not in
    -> (select id
    -> from student
    -> where sex ='男');
+--------+
| name   |
+--------+
| 张三   |
| Green  |
| 零零七 |
+--------+
3 rows in set (0.36 sec)

子查询的功能也可以通过连接查询完成,但是子查询使得 MySQL 代码更容易阅读和编写。

实例:在 student 表中查询 address 等于“北京”的学生 id,然后在 student 表中查询所有该学生的姓名,输入的 SQL 语句和执行过程如下所示。

mysql> select name from student
    -> where id =
    -> (select id
    -> from student
    -> where address = '北京' limit 1);
+------+
| name |
+------+
| 张三 |
+------+
1 row in set (0.00 sec)

如果不加 limit 1 此处会报一个 ‘Subquery returns more than 1 row’ 错误,意思时查询结果多于一行。在子查询条件语句加limit 1,找到一个符合条件的就可以了。

6.18 MySQL 分组查询

在 MySQL SELECT 语句中,允许使用 GROUP BY 子句,将结果集中的数据行根据选择列的值进行逻辑分组,以便能汇总表内容的子集,实现对每个组而不是对整个结果集进行整合。

语法格式如下:

GROUP BY { <列名> | <表达式> | <位置> } [ASC | DESC]

语法说明如下:

  • <列名>:指定用于分组的列。可以指定多个列,彼此间用逗号分隔。
  • <表达式>:指定用于分组的表达式。通常与聚合函数一块使用,例如可将表达式 COUNT(*)AS’ 人数 ’ 作为 SELECT 选择列表清单的一项。
  • <位置>:指定用于分组的选择列在 SELECT 语句结果集中的位置,通常是一个正整数。例如,GROUP BY 2 表示根据 SELECT 语句列清单上的第 2 列的值进行逻辑分组。
  • ASC|DESC:关键字 ASC 表示按升序分组,关键字 DESC 表示按降序分组,其中 ASC 为默认值,注意这两个关键字必须位于对应的列名、表达式、列的位置之后。

注意:GROUP BY 子句中的各选择列必须也是 SELECT 语句的选择列清单中的一项。

对于 GROUP BY 子句的使用,需要注意以下几点。

  • GROUP BY 子句可以包含任意数目的列,使其可以对分组进行嵌套,为数据分组提供更加细致的控制。
  • GROUP BY 子句列出的每个列都必须是检索列或有效的表达式,但不能是聚合函数。若在 SELECT 语句中使用表达式,则必须在 GROUP BY 子句中指定相同的表达式。
  • 除聚合函数之外,SELECT 语句中的每个列都必须在 GROUP BY 子句中给出。
  • 若用于分组的列中包含有 NULL 值,则 NULL 将作为一个单独的分组返回;若该列中存在多个 NULL 值,则将这些 NULL 值所在的行分为一组。

实例:根据 sex 对 student 表中的数据进行分组,将每个学院的学生姓名显示出来,输入的SQL语句和执行结果如下所示。

mysql> select sex, group_concat(name) as names
    -> from student
    -> group by sex;
+-----+------------------------+
| sex | names                  |
+-----+------------------------+
|| 张三,Green,零零七      |
|| 李四,Jim,John,Tom,王五 |
+-----+------------------------+
2 rows in set (0.00 sec)

由运行结果可以看出,根据 sex 的不同分别统计了 sex 相同的姓名。

6.19 MySQL 指定过滤条件

在 MySQL SELECT 语句中,除了能使用 GROUP BY 子句分组数据外,还可以使用 HAVING 子句过滤分组,在结果集中规定了包含哪些分组和排除哪些分组。

语法格式如下:

HAVING <条件>

其中,<条件>指的是指定的过滤条件。

HAVING 子句和 WHERE 子句非常相似,HAVING 子句支持 WHERE 子句中所有的操作符和语法,但是两者存在几点差异:

  • WHERE 子句主要用于过滤数据行,而 HAVING 子句主要用于过滤分组,即 HAVING 子句基于分组的聚合值而不是特定行的值来过滤数据,主要用来过滤分组。
  • WHERE 子句不可以包含聚合函数,HAVING 子句中的条件可以包含聚合函数。
  • HAVING 子句是在数据分组后进行过滤,WHERE 子句会在数据分组前进行过滤。WHERE 子句排除的行不包含在分组中,可能会影响 HAVING 子句基于这些值过滤掉的分组。

实例:根据 address 对 student 表中的数据进行分组,并显示学生人数大于1的分组信息,输入的 SQL 语句和执行结果如下所示。

mysql> select address, group_concat(name) as names
    -> from student
    -> group by address
    -> having count(name) > 1;
+---------+-----------------+
| address | names           |
+---------+-----------------+
| 北京    | 张三,Green,John |
+---------+-----------------+
1 row in set (0.00 sec)

6.20 MySQL 正则表达式查询

MySQL 中正式表达式通常被用来检索或替换符合某个模式的文本内容,根据指定的匹配模式匹配文中符合要求的特殊字符串。

例如,从一个文件中提取电话号码,查找一篇文章中重复的单词或替换用户输入的敏感语汇等,这些地方都可以使用正则表达式。正则表达式强大而且灵活,常用于复杂的查询。

MySQL 中使用 REGEXP 关键字指定正则表达式的字符匹配模式,下表列出了 REGEXP 操作符中常用的匹配列表。

选项 说明 例子 匹配值示例
^ 匹配文本的开始字符 ‘^b’ 匹配以字母 b 开头 的字符串 book、big、banana、 bike
$ 匹配文本的结束字符 'st$’ 匹配以 st 结尾的字 符串 test、resist、persist
. 匹配任何单个字符 'b.t’ 匹配任何 b 和 t 之间有一个字符 bit、bat、but、bite
* 匹配零个或多个在它前面的字 符 'f*n’ 匹配字符 n 前面有 任意个字符 f fn、fan、faan、abcn
+ 匹配前面的字符 1 次或多次 'ba+’ 匹配以 b 开头,后 面至少紧跟一个 a ba、bay、bare、battle
<字符串> 匹配包含指定字符的文本 'fa’ fan、afa、faad
[字符集合] 匹配字符集合中的任何一个字 符 '[xz]'匹配 x 或者 z dizzy、zebra、x-ray、 extra
[^] 匹配不在括号中的任何字符 '[^abc]’ 匹配任何不包 含 a、b 或 c 的字符串 desk、fox、f8ke
字符串{n,} 匹配前面的字符串至少 n 次 b{2} 匹配 2 个或更多 的 b bbb、 bbbb、 bbbbbbb
字符串 {n,m} 匹配前面的字符串至少 n 次, 至多 m 次 b{2,4} 匹配最少 2 个, 最多 4 个 b bbb、 bbbb

7. 函数

详情查看官网:https://dev.mysql.com/doc/refman/5.7/en/func-op-summary-ref.html

7.1 常用函数

1. 数学函数

数学函数是 MySQL 中常用的一类函数。主要用于处理数字,包括整型、浮点数等。数学函数包括绝对值函数、正弦函数、余弦函数、获取随机数的函数等。

  • ABS(X):返回 X 的绝对值

    mysql> SELECT ABS(-9);
    +---------+
    | ABS(-9) |
    +---------+
    |       9 |
    +---------+
    1 row in set (0.04 sec)
    
  • CEILING(X):对 X 向上取整

    mysql> SELECT CEILING(9.4);
    +--------------+
    | CEILING(9.4) |
    +--------------+
    |           10 |
    +--------------+
    1 row in set (0.04 sec)
    
  • FLOOR(X):对 X 向下取整

    mysql> SELECT FLOOR(9.4);
    +------------+
    | FLOOR(9.4) |
    +------------+
    |          9 |
    +------------+
    1 row in set (0.00 sec)
    
  • RAND():返回一个 0~1之间的随机数

    mysql> SELECT RAND();
    +-------------------+
    | RAND()            |
    +-------------------+
    | 0.609119029351621 |
    +-------------------+
    1 row in set (0.00 sec)
    
  • SIGN(X):判断一个属的符号 0 -> 0 负数 -> -1 正数 -> 1

    mysql> SELECT SIGN(10);
    +----------+
    | SIGN(10) |
    +----------+
    |        1 |
    +----------+
    1 row in set (0.00 sec)
    
    mysql> SELECT SIGN(-10);
    +-----------+
    | SIGN(-10) |
    +-----------+
    |        -1 |
    +-----------+
    1 row in set (0.00 sec)
    
    mysql> SELECT SIGN(0);
    +---------+
    | SIGN(0) |
    +---------+
    |       0 |
    +---------+
    1 row in set (0.00 sec)
    
  • ROUND(X):返回参数 X 的四舍五入的一个整数

    mysql> SELECT ROUND(1.23);
    +-------------+
    | ROUND(1.23) |
    +-------------+
    |           1 |
    +-------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT ROUND(-1.23);
    +--------------+
    | ROUND(-1.23) |
    +--------------+
    |           -1 |
    +--------------+
    1 row in set (0.00 sec)
    
  • MOD(N,M) 或 %:返回 N 被 M 除的余数

    mysql> SELECT MOD(15,7);
    +-----------+
    | MOD(15,7) |
    +-----------+
    |         1 |
    +-----------+
    1 row in set (0.00 sec)
    
    mysql> SELECT 15%7;
    +------+
    | 15%7 |
    +------+
    |    1 |
    +------+
    1 row in set (0.00 sec)
    

2. 字符串函数

  • CHAR_LENGTH(‘xx’):字符串长度

    mysql> SELECT CHAR_LENGTH('月上柳梢头');
    +---------------------------+
    | CHAR_LENGTH('月上柳梢头') |
    +---------------------------+
    |                         5 |
    +---------------------------+
    1 row in set (0.00 sec)
    
  • SELECT CONCAT(‘xx’, ‘xx’,‘xx’):拼接字符串

    mysql> SELECT CONCAT('人约','黄昏','后');
    +----------------------------+
    | CONCAT('人约','黄昏','后') |
    +----------------------------+
    | 人约黄昏后                 |
    +----------------------------+
    1 row in set (0.00 sec)
    
  • SELECT INSERT(‘xxx’, 1,2, ‘x’:查询,从某个位置开始替换某个长度

    mysql> SELECT INSERT('人生若只如初见,何事秋风悲画扇', 1,2, '初见');
    +-------------------------------------------------------+
    | INSERT('人生若只如初见,何事秋风悲画扇', 1,2, '初见') |
    +-------------------------------------------------------+
    | 初见若只如初见,何事秋风悲画扇                        |
    +-------------------------------------------------------+
    1 row in set (0.01 sec)
    
  • SELECT INSTR(‘xxxxx’,‘xx’) – 返回第一次出现的字串的索

    mysql> SELECT INSTR('人生若只如初见,何事秋风悲画扇','初见') ;
    +------------------------------------------------+
    | INSTR('人生若只如初见,何事秋风悲画扇','初见') |
    +------------------------------------------------+
    |                                              6 |
    +------------------------------------------------+
    1 row in set (0.03 sec)
    
  • SELECT REPLACE(‘xxxx’, ‘xx’, ‘x’) :替换

    mysql> SELECT REPLACE('人生若只如初见,何事秋风悲画扇', '何事秋风悲画扇', '却道故人心易变');
    +-------------------------------------------------------------------------------+
    | REPLACE('人生若只如初见,何事秋风悲画扇', '何事秋风悲画扇', '却道故人心易变') |
    +-------------------------------------------------------------------------------+
    | 人生若只如初见,却道故人心易变                                                |
    +-------------------------------------------------------------------------------+
    1 row in set (0.00 sec)
    
  • SELECT SUBSTR(‘xxxxxxxxx’,2,5) :截取指定长度

    mysql> SELECT SUBSTR('人生若只如初见',3,5);
    +------------------------------+
    | SUBSTR('人生若只如初见',3,5) |
    +------------------------------+
    | 若只如初见                   |
    +------------------------------+
    1 row in set (0.00 sec)
    
  • SELECT REVERSE(‘xxx’) – 反转

    mysql> SELECT REVERSE('Alice');
    +------------------+
    | REVERSE('Alice') |
    +------------------+
    | ecilA            |
    +------------------+
    1 row in set (0.00 sec)
    
  • SELECT LOWER(‘xxx’) – 小写字母

    mysql> SELECT LOWER('Numb');
    +---------------+
    | LOWER('Numb') |
    +---------------+
    | numb          |
    +---------------+
    1 row in set (0.00 sec)
    
  • SELECT UPPER(‘xxx’) – 大写字母

    mysql> SELECT UPPER('Numb');
    +---------------+
    | UPPER('Numb') |
    +---------------+
    | NUMB          |
    +---------------+
    1 row in set (0.00 sec)
    
  • SELECT ASCII(str):返回字符串 str 最左面字符的 ASCII 值。如果 str 是空字符串,返回 0。如果 str 是 NULL,返回 NULL。

    mysql> SELECT ASCII('2');
    +------------+
    | ASCII('2') |
    +------------+
    |         50 |
    +------------+
    1 row in set (0.03 sec)
    
    mysql> SELECT ASCII(2);
    +----------+
    | ASCII(2) |
    +----------+
    |       50 |
    +----------+
    1 row in set (0.00 sec)
    
    mysql> SELECT ASCII('dx');
    +-------------+
    | ASCII('dx') |
    +-------------+
    |         100 |
    +-------------+
    1 row in set (0.00 sec)
    

3. 时间和日期函数

  • SELECT CURRENT_DATE():获取当前日期(以‘YYYY-MM-DD’或YYYYMMDD格式返回今天日期值,取决于函数在一个字符串还是数字上下文被使用。)

    mysql> SELECT CURRENT_DATE();
    +----------------+
    | CURRENT_DATE() |
    +----------------+
    | 2020-01-29     |
    +----------------+
    1 row in set (0.00 sec)
    
  • SELECT CURDATE():获取当前日期

    mysql> SELECT CURDATE();
    +------------+
    | CURDATE()  |
    +------------+
    | 2020-01-29 |
    +------------+
    1 row in set (0.00 sec)
    
  • SELECT NOW():获取当前的时间(以‘YYYY-MM-DD HH:MM:SS’或YYYYMMDDHHMMSS格式返回当前的日期和时间 )

    mysql> SELECT NOW();
    +---------------------+
    | NOW()               |
    +---------------------+
    | 2020-01-29 14:17:39 |
    +---------------------+
    1 row in set (0.00 sec)
    
  • SELECT LOCALTIME():本地时间

    mysql> SELECT LOCALTIME();
    +---------------------+
    | LOCALTIME()         |
    +---------------------+
    | 2020-01-29 14:17:51 |
    +---------------------+
    1 row in set (0.00 sec)
    
  • SELECT SYSDATE():系统时间

    mysql> SELECT SYSDATE();
    +---------------------+
    | SYSDATE()           |
    +---------------------+
    | 2020-01-29 14:18:04 |
    +---------------------+
    1 row in set (0.03 sec)
    
  • SELECT YEAR(NOW()):获取当前年

    mysql> SELECT YEAR(NOW());
    +-------------+
    | YEAR(NOW()) |
    +-------------+
    |        2020 |
    +-------------+
    1 row in set (0.03 sec)
    
  • SELECT MONTH(NOW()):获取当前月

    mysql> SELECT MONTH(NOW());
    +--------------+
    | MONTH(NOW()) |
    +--------------+
    |            1 |
    +--------------+
    1 row in set (0.00 sec)
    
  • SELECT DAY(NOW()):获取当前日

    mysql> SELECT DAY(NOW());
    +------------+
    | DAY(NOW()) |
    +------------+
    |         29 |
    +------------+
    1 row in set (0.04 sec)
    
  • SELECT HOUR(NOW()):获取当前时

    mysql> SELECT HOUR(NOW());
    +-------------+
    | HOUR(NOW()) |
    +-------------+
    |          14 |
    +-------------+
    1 row in set (0.00 sec)
    
  • SELECT MINUTE(NOW()) :获取当前分

    mysql> SELECT MINUTE(NOW());
    +---------------+
    | MINUTE(NOW()) |
    +---------------+
    |            19 |
    +---------------+
    1 row in set (0.00 sec)
    
  • SELECT SECOND(NOW()):获取当前秒

    mysql> SELECT SECOND(NOW());
    +---------------+
    | SECOND(NOW()) |
    +---------------+
    |            34 |
    +---------------+
    1 row in set (0.00 sec)
    

4. 系统信息函数

系统信息函数用来查询MySQL数据库的系统信息。例如,查询数据库的版本,查询数据库的当前用户等。本小节将详细讲解系统信息函数的作用和使用方法。

  • VERSION():函数返回数据库的版本号;

    mysql> SELECT VERSION();
    +-----------+
    | VERSION() |
    +-----------+
    | 5.7.19    |
    +-----------+
    1 row in set (0.00 sec)
    
  • CONNECTION_ID():函数返回服务器的连接数,也就是到现在为止MySQL服务的连接次数;

    mysql> SELECT CONNECTION_ID();
    +-----------------+
    | CONNECTION_ID() |
    +-----------------+
    |              11 |
    +-----------------+
    1 row in set (0.00 sec)
    
  • DATABASE()和SCHEMA():返回当前数据库名;

    mysql> SELECT DATABASE();
    +------------+
    | DATABASE() |
    +------------+
    | school     |
    +------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT SCHEMA();
    +----------+
    | SCHEMA() |
    +----------+
    | school   |
    +----------+
    1 row in set (0.00 sec)
    
  • 获取用户名的函数:USER()、SYSTEM_USER()、SESSION_USER()、CURRENT_USER()和CURRENT_USER这几个函数可以返回当前用户的名;

    mysql> SELECT USER();
    +----------------+
    | USER()         |
    +----------------+
    | root@localhost |
    +----------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT SYSTEM_USER();
    +----------------+
    | SYSTEM_USER()  |
    +----------------+
    | root@localhost |
    +----------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT SESSION_USER();
    +----------------+
    | SESSION_USER() |
    +----------------+
    | root@localhost |
    +----------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT CURRENT_USER();
    +----------------+
    | CURRENT_USER() |
    +----------------+
    | root@localhost |
    +----------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT CURRENT_USER;
    +----------------+
    | CURRENT_USER   |
    +----------------+
    | root@localhost |
    +----------------+
    1 row in set (0.00 sec)
    
  • 获取字符串的字符集和排序方式的函数:

    • CHARSET(str)函数返回字符串str的字符集,一般情况这个字符集就是系统的默认字符集;

      mysql> select charset('Numb');
      +-----------------+
      | charset('Numb') |
      +-----------------+
      | gbk             |
      +-----------------+
      1 row in set (0.00 sec)
      
    • COLLATION(str)函数返回字符串str的字符排列方式;

      +-------------------+
      | collation('Numb') |
      +-------------------+
      | gbk_chinese_ci    |
      +-------------------+
      1 row in set (0.00 sec)
      
  • 获取最后一个自动生成的ID值的函数:LAST_INSERT_ID()函数返回最后生成的AUTO_INCREMENT值。

    mysql> select last_insert_id();
    +------------------+
    | last_insert_id() |
    +------------------+
    |                0 |
    +------------------+
    1 row in set (0.02 sec)
    

7.2 聚合函数

函数名称 描述
COUNT() 计数
SUM() 求和
AVG() 平均值
MAX() 最大值
MIN() 最小值

7.3 加密函数

加密函数是 MySQL 中用来对数据进行加密的函数。

因为数据库中有些很敏感的信息不希望被其他人看到,就应该通过加密方式来使这些数据变成看似乱码的数据。例如用户的密码,就应该经过加密。

下面是各种加密函数的名称、作用和使用方法。

1. 加密函数 PASSWORD(str)

PASSWORD(str) 函数可以对字符串str进行加密。

一般情况下,PASSWORD(str)函数主要是用来给用户的密码加密的。

下面使用PASSWORD(str)函数为字符串“abcd”加密。

mysql> SELECT PASSWORD('123456');
+-------------------------------------------+
| PASSWORD('123456')                        |
+-------------------------------------------+
| *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
+-------------------------------------------+
1 row in set, 1 warning (0.03 sec)

2. 加密函数 MD5(str)

MD5(str) 函数可以对字符串str进行加密。

MD5(str) 函数主要对普通的数据进行加密。

下面使用MD5(str)函数为字符串“abcd”加密。

mysql> SELECT MD5('123456');
+----------------------------------+
| MD5('123456')                    |
+----------------------------------+
| e10adc3949ba59abbe56e057f20f883e |
+----------------------------------+
1 row in set (0.00 sec)

3. 加密函数 ENCODE(str,pswd_str)、解密函数 DECODE(crypt_str,pswd_str)

  • ENCODE(str,pswd_str) 函数可以使用字符串 pswd_str 来加密字符串 str 。

    加密的结果是一个二进制数,必须使用 BLOB 类型的字段来保存它。

  • DECODE(crypt_str,pswd_str) 函数可以使用字符串 pswd_str 来为 crypt_str 解密。

    • crypt_str 是通过 ENCODE(str,pswd_str) 加密后的二进制数据。
    • 字符串 pswd_str 应该与加密时的字符串 pswd_str 是相同的。

下面使用 DECODE(crypt_str,pswd_str) 为 ENCODE(str,pswd_str) 加密的数据解密。

mysql> SELECT DECODE(ENCODE('123456','evan'),'evan');
+----------------------------------------+
| DECODE(ENCODE('123456','evan'),'evan') |
+----------------------------------------+
| 123456                                 |
+----------------------------------------+
1 row in set, 2 warnings (0.00 sec)

7.4 自定义函数

在使用 MySQL 的过程中,MySQL 自带的函数可能完成不了我们的业务需求,这时候就需要自定义函数。

自定义函数是一种与存储过程十分相似的过程式数据库对象。它与存储过程一样,都是由 SQL 语句和过程式语句组成的代码片段,并且可以被应用程序和其他 SQL 语句调用。

自定义函数与存储过程之间存在几点区别:

  • 自定义函数不能拥有输出参数,这是因为自定义函数自身就是输出参数;而存储过程可以拥有输出参数。
  • 自定义函数中必须包含一条 RETURN 语句,而这条特殊的 SQL 语句不允许包含于存储过程中。
  • 可以直接对自定义函数进行调用而不需要使用 CALL 语句,而对存储过程的调用需要使用 CALL 语句。

1. 创建并使用自定义函数

可以使用 CREATE FUNCTION 语句创建自定义函数。

语法格式如下:

CREATE FUNCTION <函数名> ( [ <参数1> <类型1> [ , <参数2> <类型2>] ])
  RETURNS <类型>
  <函数主体>

语法说明如下:

  • <函数名>:指定自定义函数的名称。注意,自定义函数不能与存储过程具有相同的名称。
  • <参数><类型>:用于指定自定义函数的参数。这里的参数只有名称和类型,不能指定关键字 IN、OUT 和 INOUT。
  • RETURNS<类型>:用于声明自定义函数返回值的数据类型。其中,<类型>用于指定返回值的数据类型。
  • <函数主体>:自定义函数的主体部分,也称函数体。所有在存储过程中使用的 SQL 语句在自定义函数中同样适用,包括前面所介绍的局部变量、SET 语句、流程控制语句、游标等。除此之外,自定义函数体还必须包含一个 RETURN<值> 语句,其中<值>用于指定自定义函数的返回值。

在 RETURN VALUE 语句中包含 SELECT 语句时,SELECT 语句的返回结果只能是一行且只能有一列值。

若要查看数据库中存在哪些自定义函数,可以使用 SHOW FUNCTION STATUS 语句;

若要查看数据库中某个具体的自定义函数,可以使用 SHOW CREATE FUNCTION<函数名> 语句,其中<函数名>用于指定该自定义函数的名称。

实例:创建存储函数,名称为 StuNameById,该函数返回 SELECT 语句的查询结果,数值类型为字符串类型,输入的 SQL 语句和执行结果如下所示。

mysql> CREATE FUNCTION StuNameById()
    -> RETURNS VARCHAR(40)
    -> RETURN
    -> (SELECT name FROM student
    -> WHERE id = 1);
Query OK, 0 rows affected (0.33 sec)

成功创建自定义函数后,就可以如同调用系统内置函数一样,使用关键字 SELECT 调用用户自定义的函数,语法格式为:

 SELECT <自定义函数名> ([<参数> [,...]])

实例:调用自定义函数 StuNameById,查看函数的运行结果,如下所示。

mysql> SELECT StuNameById();
+---------------+
| StuNameById() |
+---------------+
| 张三          |
+---------------+
1 row in set (0.04 sec)

2. 修改自定义函数

可以使用 ALTER FUNCTION 语句来修改自定义函数的某些相关特征。

若要修改自定义函数的内容,则需要先删除该自定义函数,然后重新创建。

3. 删除自定义函数

自定义函数被创建后,一直保存在数据库服务器上以供使用,直至被删除。

删除自定义函数的方法与删除存储过程的方法基本一样,可以使用 DROP FUNCTION 语句来实现。

语法格式如下:

DROP FUNCTION [ IF EXISTS ] <自定义函数名>

语法说明如下。

  • <自定义函数名>:指定要删除的自定义函数的名称。
  • IF EXISTS:指定关键字,用于防止因误删除不存在的自定义函数而引发错误。

实例:删除自定义函数 StuNameById,查看函数的运行结果,如下所示。

mysql> DROP FUNCTION StuNameById;
Query OK, 0 rows affected (0.02 sec)

mysql> SELECT StuNameById();
ERROR 1305 (42000): FUNCTION school.StuNameById does not exist

8. 索引

索引是 MySQL 数据库中的重要对象之一,用于快速找出某个列中有某一特定值的行。

8.1 为什么要使用索引

索引是 MySQL 中一种十分重要的数据库对象。它是数据库性能调优技术的基础,常用于实现数据的快速检索。

索引就是根据表中的一列或若干列按照一定顺序建立的列值与记录行之间的对应关系表,实质上是一张描述索引列的列值与原表中记录行之间一一对应关系的有序表

在 MySQL 中,通常有以下两种方式访问数据库表的行数据:

1. 顺序访问

顺序访问是在表中实行全表扫描,从头到尾逐行遍历,直到在无序的行数据中找到符合条件的目标数据。这种方式实现比较简单,但是当表中有大量数据的时候,效率非常低下。例如,在几千万条数据中查找少量的数据时,使用顺序访问方式将会遍历所有的数据,花费大量的时间,显然会影响数据库的处理性能。

2. 索引访问

索引访问是通过遍历索引来直接访问表中记录行的方式。使用这种方式的前提是对表建立一个索引,在列上创建了索引之后,查找数据时可以直接根据该列上的索引找到对应记录行的位置,从而快捷地查找到数据。索引存储了指定列数据值的指针,根据指定的排序顺序对这些指针排序。

例如,在学生基本信息表 students 中,如果基于 student_id 建立了索引,系统就建立了一张索引列到实际记录的映射表,当用户需要查找 student_id 为 12022 的数据的时候,系统先在 student_id 索引上找到该记录,然后通过映射表直接找到数据行,并且返回该行数据。因为扫描索引的速度一般远远大于扫描实际数据行的速度,所以采用索引的方式可以大大提高数据库的工作效率。

8.2 索引的分类

索引的类型和存储引擎有关,每种存储引擎所支持的索引类型不一定完全相同。

根据存储方式的不同,MySQL 中常用的索引在物理上分为以下两类。

1. B-树索引

B-树索引又称为 BTREE 索引,目前大部分的索引都是采用 B-树索引来存储的。B-树索引是一个典型的数据结构,其包含的组件主要有以下几个:

  • 叶子节点:包含的条目直接指向表里的数据行。叶子节点之间彼此相连,一个叶子节点有一个指向下一个叶子节点的指针。
  • 分支节点:包含的条目指向索引里其他的分支节点或者叶子节点。
  • 根节点:一个 B-树索引只有一个根节点,实际上就是位于树的最顶端的分支节点。

基于这种树形数据结构,表中的每一行都会在索引上有一个对应值。因此,在表中进行数据查询时,可以根据索引值一步一步定位到数据所在的行。

B-树索引可以进行全键值、键值范围和键值前缀查询,也可以对查询结果进行 ORDER BY 排序。但 B-树索引必须遵循左边前缀原则,要考虑以下几点约束:

  • 查询必须从索引的最左边的列开始。
  • 查询不能跳过某一索引列,必须按照从左到右的顺序进行匹配。
  • 存储引擎不能使用索引中范围条件右边的列。

2. 哈希索引

哈希(Hash)一般翻译为“散列”,也有直接音译成“哈希”的,就是把任意长度的输入(又叫作预映射,pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。

哈希索引也称为散列索引或 HASH 索引。MySQL 目前仅有 MEMORY 存储引擎和 HEAP 存储引擎支持这类索引。其中,MEMORY 存储引擎可以支持 B- 树索引和 HASH 索引,且将 HASH 当成默认索引。

HASH 索引不是基于树形的数据结构查找数据,而是根据索引列对应的哈希值的方法获取表的记录行。哈希索引的最大特点是访问速度快,但也存在下面的一些缺点:

  • MySQL 需要读取表中索引列的值来参与散列计算,散列计算是一个比较耗时的操作。也就是说,相对于 B- 树索引来说,建立哈希索引会耗费更多的时间。
  • 不能使用 HASH 索引排序。
  • HASH 索引只支持等值比较,如“=”“IN()”或“<=>”。
  • HASH 索引不支持键的部分匹配,因为在计算 HASH 值的时候是通过整个索引值来计算的。

根据索引的具体用途,MySQL 中的索引在逻辑上分为以下 5 类:

1. 普通索引

普通索引是最基本的索引类型,唯一任务是加快对数据的访问速度,没有任何限制。创建普通索引时,通常使用的关键字是 INDEX 或 KEY。

2. 唯一性索引

唯一性索引是不允许索引列具有相同索引值的索引。如果能确定某个数据列只包含彼此各不相同的值,在为这个数据列创建索引的时候就应该用关键字 UNIQUE 把它定义为一个唯一性索引。

创建唯一性索引的目的往往不是为了提高访问速度,而是为了避免数据出现重复。

3. 主键索引

主键索引是一种唯一性索引,即不允许值重复或者值为空,并且每个表只能有一个主键。主键可以在创建表的时候指定,也可以通过修改表的方式添加,必须指定关键字 PRIMARY KEY。

注意:主键是数据库考察的重点。注意每个表只能有一个主键。

4. 空间索引

空间索引主要用于地理空间数据类型 GEOMETRY。

5. 全文索引

全文索引只能在 VARCHAR 或 TEXT 类型的列上创建,并且只能在 MyISAM 表中创建。

索引在逻辑上分为以上 5 类,但在实际使用中,索引通常被创建成单列索引和组合索引。

  • 单列索引就是索引只包含原表的一个列。
  • 组合索引也称为复合索引或多列索引,相对于单列索引来说,组合索引是将原表的多个列共同组成一个索引。

提示:一个表可以有多个单列索引,但这些索引不是组合索引。一个组合索引实质上为表的查询提供了多个索引,以此来加快查询速度。比如,在一个表中创建了一个组合索引(c1,c2,c3),在实际查询中,系统用来实际加速的索引有三个:单个索引(c1)、双列索引(c1,c2)和多列索引(c1,c2,c3)。

为了提高索引的应用性能,MySQL中的索引可以根据具体应用采用不同的索引策略。这些索引策略所对应的索引类型有聚集索引、次要索引、覆盖索引、复合索引、前缀索引、唯一索引等。

8.3 索引的使用原则和注意事项

虽然索引可以加快查询速度,提高 MySQL 的处理性能,但是过多地使用索引也会造成以下弊端:

  • 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
  • 除了数据表占数据空间之外,每一个索引还要占一定的物理空间。如果要建立聚簇索引,那么需要的空间就会更大。
  • 当对表中的数据进行增加、删除和修改的时候,索引也要动态地维护,这样就降低了数据的维护速度。

注意:索引可以在一些情况下加速查询,但是在某些情况下,会降低效率。

索引只是提高效率的一个因素,因此在建立索引的时候应该遵循以下原则:

  • 在经常需要搜索的列上建立索引,可以加快搜索的速度。
  • 在作为主键的列上创建索引,强制该列的唯一性,并组织表中数据的排列结构。
  • 在经常使用表连接的列上创建索引,这些列主要是一些外键,可以加快表连接的速度。
  • 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,所以其指定的范围是连续的。
  • 在经常需要排序的列上创建索引,因为索引已经排序,所以查询时可以利用索引的排序,加快排序查询。
  • 在经常使用 WHERE 子句的列上创建索引,加快条件的判断速度。

与此对应,在某些应用场合下建立索引不能提高 MySQL 的工作效率,甚至在一定程度上还带来负面效应,降低了数据库的工作效率,一般来说不适合创建索引的环境如下:

  • 对于那些在查询中很少使用或参考的列不应该创建索引。因为这些列很少使用到,所以有索引或者无索引并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度,并增大了空间要求。
  • 对于那些只有很少数据值的列也不应该创建索引。因为这些列的取值很少,例如人事表的性别列。查询结果集的数据行占了表中数据行的很大比例,增加索引并不能明显加快检索速度。
  • 对于那些定义为 TEXT、IMAGE 和 BIT 数据类型的列不应该创建索引。因为这些列的数据量要么相当大,要么取值很少。
  • 当修改性能远远大于检索性能时,不应该创建索引。因为修改性能和检索性能是互相矛盾的。当创建索引时,会提高检索性能,降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。

8.4 创建索引

索引的建立对于 MySQL 数据库的高效运行是很重要的,索引可以大大提升 MySQL 的检索速度。

1. 基本语法

MySQL 提供了三种创建索引的方法:

1) 使用 CREATE INDEX 语句

可以使用专门用于创建索引的 CREATE INDEX 语句在一个已有的表上创建索引,但该语句不能创建主键。

语法格式:

CREATE <索引名> ON <表名> (<列名> [<长度>] [ ASC | DESC])

语法说明如下:

  • <索引名>:指定索引名。一个表可以创建多个索引,但每个索引在该表中的名称是唯一的。
  • <表名>:指定要创建索引的表名。
  • <列名>:指定要创建索引的列名。通常可以考虑将查询语句中在 JOIN 子句和 WHERE 子句里经常出现的列作为索引列。
  • <长度>:可选项。指定使用列前的 length 个字符来创建索引。使用列的一部分创建索引有利于减小索引文件的大小,节省索引列所占的空间。在某些情况下,只能对列的前缀进行索引。索引列的长度有一个最大上限 255 个字节(MyISAM 和 InnoDB 表的最大上限为 1000 个字节),如果索引列的长度超过了这个上限,就只能用列的前缀进行索引。另外,BLOB 或 TEXT 类型的列也必须使用前缀索引。
  • ASC|DESC:可选项。ASC指定索引按照升序来排列,DESC指定索引按照降序来排列,默认为ASC

2) 使用 CREATE TABLE 语句

索引也可以在创建表(CREATE TABLE)的同时创建。在 CREATE TABLE 语句中添加以下语句。

语法格式:

CONSTRAINT PRIMARY KEY [索引类型] (<列名>,)

在 CREATE TABLE 语句中添加此语句,表示在创建新表的同时创建该表的主键。

语法格式:

KEY | INDEX [<索引名>] [<索引类型>] (<列名>,)

在 CREATE TABLE 语句中添加此语句,表示在创建新表的同时创建该表的索引。

语法格式:

UNIQUE [ INDEX | KEY] [<索引名>] [<索引类型>] (<列名>,)

在 CREATE TABLE 语句中添加此语句,表示在创建新表的同时创建该表的唯一性索引。

语法格式:

FOREIGN KEY <索引名> <列名>

在 CREATE TABLE 语句中添加此语句,表示在创建新表的同时创建该表的外键。

在使用 CREATE TABLE 语句定义列选项的时候,可以通过直接在某个列定义后面添加 PRIMARY KEY 的方式创建主键。而当主键是由多个列组成的多列索引时,则不能使用这种方法,只能用在语句的最后加上一个 PRIMARY KRY(<列名>,…) 子句的方式来实现。

3) 使用 ALTER TABLE 语句

CREATE INDEX 语句可以在一个已有的表上创建索引,ALTER TABLE 语句也可以在一个已有的表上创建索引。在使用 ALTER TABLE 语句修改表的同时,可以向已有的表添加索引。具体的做法是在 ALTER TABLE 语句中添加以下语法成分的某一项或几项。

语法格式:

ADD INDEX [<索引名>] [<索引类型>] (<列名>,)

在 ALTER TABLE 语句中添加此语法成分,表示在修改表的同时为该表添加索引。

语法格式:

ADD PRIMARY KEY [<索引类型>] (<列名>,)

在 ALTER TABLE 语句中添加此语法成分,表示在修改表的同时为该表添加主键。

语法格式:

ADD UNIQUE [ INDEX | KEY] [<索引名>] [<索引类型>] (<列名>,)

在 ALTER TABLE 语句中添加此语法成分,表示在修改表的同时为该表添加唯一性索引。

语法格式:

ADD FOREIGN KEY [<索引名>] (<列名>,)

在 ALTER TABLE 语句中添加此语法成分,表示在修改表的同时为该表添加外键。

2. 创建一般索引

实例:创建一个表 test10,在该表的 height 字段创建一般索引。输入的 SQL 语句和执行过程如下所示。

mysql> create table test10
    -> (
    -> id int not null,
    -> name varchar(40) default null,
    -> dept_id int default null,
    -> age int default null,
    -> height int default null,
    -> index(height)
    -> );
Query OK, 0 rows affected (0.55 sec)

mysql> show create table test10\G
*************************** 1. row ***************************
       Table: test10
Create Table: CREATE TABLE `test10` (
  `id` int(11) NOT NULL,
  `name` varchar(40) DEFAULT NULL,
  `dept_id` int(11) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `height` int(11) DEFAULT NULL,
  KEY `height` (`height`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

3. 创建唯一索引

实例:创建一个表 test11,在该表的 id 字段上使用 UNIQUE 关键字创建唯一索引。输入的 SQL 语句和执行过程如下所示。

mysql> CREATE TABLE test11
    -> (
    -> id INT NOT NULL,
    -> name VARCHAR(40) DEFAULT NULL,
    -> dept_id INT DEFAULT NULL,
    -> age INT DEFAULT NULL,
    -> height INT DEFAULT NULL,
    -> UNIQUE INDEX(height)
    -> );
Query OK, 0 rows affected (0.94 sec)

mysql> SHOW CREATE TABLE test11\G
*************************** 1. row ***************************
       Table: test11
Create Table: CREATE TABLE `test11` (
  `id` int(11) NOT NULL,
  `name` varchar(40) DEFAULT NULL,
  `dept_id` int(11) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `height` int(11) DEFAULT NULL,
  UNIQUE KEY `height` (`height`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

4. 查看索引

在 MySQL 中,如果要查看已创建的索引的情况,可以使用 SHOW INDEX 语句查看表中创建的索引。

语法格式:

SHOW INDEX FROM <表名> [ FROM <数据库名>]

语法说明如下:

  • <表名>:要显示索引的表。
  • <数据库名>:要显示的表所在的数据库。

显示数据库 mytest 的表 course 的索引情况。

mysql> SHOW INDEX FROM course FROM mytest;

该语句会返回一张结果表,该表有如下几个字段,每个字段所显示的内容说明如下。

  • Table:表的名称。
  • Non_unique:用于显示该索引是否是唯一索引。若不是唯一索引,则该列的值显示为 1;若是唯一索引,则该列的值显示为 0。
  • Key_name:索引的名称。
  • Seq_in_index:索引中的列序列号,从 1 开始计数。
  • Column_name:列名称。
  • Collation:显示列以何种顺序存储在索引中。在 MySQL 中,升序显示值“A”(升序),若显示为 NULL,则表示无分类。
  • Cardinality:显示索引中唯一值数目的估计值。基数根据被存储为整数的统计数据计数,所以即使对于小型表,该值也没有必要是精确的。基数越大,当进行联合时,MySQL 使用该索引的机会就越大。
  • Sub_part:若列只是被部分编入索引,则为被编入索引的字符的数目。若整列被编入索引,则为 NULL。
  • Packed:指示关键字如何被压缩。若没有被压缩,则为 NULL。
  • Null:用于显示索引列中是否包含 NULL。若列含有 NULL,则显示为 YES。若没有,则该列显示为 NO。
  • Index_type:显示索引使用的类型和方法(BTREE、FULLTEXT、HASH、RTREE)。
  • Comment:显示评注。

实例:使用 SHOW INDEX 语句查看表 test11 的索引信息,输入的 SQL 语句和执行结果如下所示。

mysql> SHOW INDEX FROM test11\G
*************************** 1. row ***************************
        Table: test11
   Non_unique: 0
     Key_name: height
 Seq_in_index: 1
  Column_name: height
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
1 row in set (0.00 sec)

8.5 修改和删除索引

在 MySQL 中修改索引可以通过删除原索引,再根据需要创建一个同名的索引,从而实现修改索引的操作。

1. 基本语法

当不再需要索引时,可以使用 DROP INDEX 语句或 ALTER TABLE 语句来对索引进行删除。

1) 使用 DROP INDEX 语句

语法格式:

DROP INDEX <索引名> ON <表名>

语法说明如下:

  • <索引名>:要删除的索引名。
  • <表名>:指定该索引所在的表名。

2) 使用 ALTER TABLE 语句

根据 ALTER TABLE 语句的语法可知,该语句也可以用于删除索引。具体使用方法是将 ALTER TABLE 语句的语法中部分指定为以下子句中的某一项。

  • DROP PRIMARY KEY:表示删除表中的主键。一个表只有一个主键,主键也是一个索引。
  • DROP INDEX index_name:表示删除名称为 index_name 的索引。
  • DROP FOREIGN KEY fk_symbol:表示删除外键。

注意:如果删除的列是索引的组成部分,那么在删除该列时,也会将该列从索引中删除;如果组成索引的所有列都被删除,那么整个索引将被删除。

2. 删除索引

实例:删除表 test10 中的索引,输入的 SQL 语句和执行结果如下所示。

mysql> DROP INDEX height
    -> ON test10;
Query OK, 0 rows affected (0.28 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SHOW CREATE TABLE test10\G
*************************** 1. row ***************************
       Table: test10
Create Table: CREATE TABLE `test10` (
  `id` int(11) NOT NULL,
  `name` varchar(40) DEFAULT NULL,
  `dept_id` int(11) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `height` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

实例:删除表 test11 中名称为 id 的索引,输入的 SQL 语句和执行结果如下所示。

mysql> ALTER TABLE test11
    -> DROP INDEX height;
Query OK, 0 rows affected (0.27 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SHOW CREATE TABLE test11\G
*************************** 1. row ***************************
       Table: test11
Create Table: CREATE TABLE `test11` (
  `id` int(11) NOT NULL,
  `name` varchar(40) DEFAULT NULL,
  `dept_id` int(11) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `height` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

9. 用户权限管理

9.1 创建用户

在对 MySQL 的日常管理和实际操作中,为了避免用户恶意冒名使用 root 账号控制数据库,通常需要创建一系列具备适当权限的账号,应该尽可能地不用或少用 root 账号登录系统,以此来确保数据的安全访问。

1. 创建用户

可以使用 CREATE USER 语句来创建一个或多个 MySQL 账户,并设置相应的口令。

语法格式:

 CREATE USER <用户名> [ IDENTIFIED ] BY [ PASSWORD ] <口令>

语法说明如下:

1) <用户名>

指定创建用户账号,格式为 ‘user_name’@‘host_name’。这里user_name是用户名,host_name为主机名,即用户连接 MySQL 时所在主机的名字。若在创建的过程中,只给出了账户的用户名,而没指定主机名,则主机名默认为“%”,表示一组主机。

2) PASSWORD

可选项,用于指定散列口令,即若使用明文设置口令,则需忽略PASSWORD关键字;若不想以明文设置口令,且知道 PASSWORD() 函数返回给密码的散列值,则可以在口令设置语句中指定此散列值,但需要加上关键字PASSWORD

3) IDENTIFIED BY子句

用于指定用户账号对应的口令,若该用户账号无口令,则可省略此子句。

4) <口令>

指定用户账号的口令,在IDENTIFIED BY关键字或PASSWOED关键字之后。给定的口令值可以是只由字母和数字组成的明文,也可以是通过 PASSWORD() 函数得到的散列值。

使用 CREATE USER 语句应该注意以下几点:

  • 如果使用 CREATE USER 语句时没有为用户指定口令,那么 MySQL 允许该用户可以不使用口令登录系统,然而从安全的角度而言,不推荐这种做法。
  • 使用 CREATE USER 语句必须拥有 MySQL 中 MySQL 数据库的 INSERT 权限或全局 CREATE USER 权限。
  • 使用 CREATE USER 语句创建一个用户账号后,会在系统自身的 MySQL 数据库的 user 表中添加一条新记录。若创建的账户已经存在,则语句执行时会出现错误。
  • 新创建的用户拥有的权限很少。他们可以登录 MySQL,只允许进行不需要权限的操作,如使用 SHOW 语句查询所有存储引擎和字符集的列表等。

如果两个用户具有相同的用户名和不同的主机名,MySQL 会将他们视为不同的用户,并允许为这两个用户分配不同的权限集合。

实例:使用 CREATE USER 创建一个用户,用户名是 numb,密码是 123456,主机是 localhost。输入的 SQL 语句和执行过程如下所示。

mysql> CREATE USER 'numb'@'localhost'
    -> IDENTIFIED BY '123456';
Query OK, 0 rows affected (0.40 sec)

在 Windows 命令行中,使用新创建的用户 numb 和密码 123456 登录数据库服务器,如下所示:

C:\Windows\system32>mysql -h localhost -u numb -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.7.19 MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

9.2 修改用户

1. 修改用户账户

可以使用 RENAME USER 语句修改一个或多个已经存在的 MySQL 用户账号。

语法格式:

RENAME USER <旧用户> TO <新用户>

语法说明如下:

  • <旧用户>:系统中已经存在的 MySQL 用户账号。
  • <新用户>:新的 MySQL 用户账号。

使用 RENAME USER 语句时应该注意以下几点:

  • RENAME USER 语句用于对原有的 MySQL 账户进行重命名。
  • 若系统中旧账户不存在或者新账户已存在,则该语句执行时会出现错误。
  • 要使用 RENAME USER 语句,必须拥有 MySQL 中的 MySQL 数据库的 UPDATE 权限或全局 CREATE USER 权限。

实例:使用 RENAME USER 语句将用户名 numb 修改为 S_numb,主机是 localhost。输入的 SQL 语句和执行过程如下所示。

mysql> RENAME USER numb@'localhost'
    -> TO S_numb@'localhost';
Query OK, 0 rows affected (0.03 sec)

在 Windows 命令行工具中,使用 jack 和密码 tiger 登录数据库服务器,如下所示。

C:\Windows\system32>mysql -h localhost -u S_numb -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.7.19 MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

2. 修改用户口令

可以使用 SET PASSWORD 语句修改一个用户的登录口令。

语法格式:

SET PASSWORD [ FOR <用户名> ] =
{
    PASSWORD('新明文口令')
    | OLD_PASSWORD('旧明文口令')
    | '加密口令值'
}

语法说明如下。

  • FOR 子句:可选项。指定欲修改口令的用户。
  • PASSWORD(‘新明文口令’):表示使用函数 PASSWORD() 设置新口令,即新口令必须传递到函数 PASSWORD() 中进行加密。
  • 加密口令值:表示已被函数 PASSWORD() 加密的口令值。

注意:PASSWORD() 函数为单向加密函数,一旦加密后不能解密出原明文。

使用 SET PASSWORD 语句应注意以下几点:

  • 在 SET PASSWORD 语句中,若不加上 FOR 子句,表示修改当前用户的口令。若加上 FOR 子句,表示修改账户为 user 的用户口令。
  • user 必须以 ‘user_name’@‘host_name’ 的格式给定,user_name 为账户的用户名,host_name 为账户的主机名。
  • 该账户必须在系统中存在,否则语句执行时会出现错误。
  • 在 SET PASSWORD 语句中,只能使用选项 PASSWORD(‘新明文口令’) 和加密口令值中的一项,且必须使用其中的一项。

实例:使用 SET 语句将用户名为 S_numb 的密码修改为 111111,主机是 localhost。输入的 SQL 语句和执行过程如下所示。

mysql> SET PASSWORD FOR 'S_numb'@'localhost'=
    -> PASSWORD('111111');
Query OK, 0 rows affected, 1 warning (0.03 sec)

在 Windows 命令行工具中,使用 jack 和密码 lion 登录数据库服务器,如下所示。

C:\Windows\system32>mysql -h localhost -u S_numb -p111111
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.7.19 MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

9.3 删除用户

MySQL 数据库中可以使用 DROP USER 语句来删除一个或多个用户账号以及相关的权限。

语法格式:

DROP USER <用户名1> [ , <用户名2> ]

使用 DROP USER 语句应该注意以下几点:

  • DROP USER 语句可用于删除一个或多个 MySQL 账户,并撤销其原有权限。
  • 使用 DROP USER 语句必须拥有 MySQL 中的 MySQL 数据库的 DELETE 权限或全局 CREATE USER 权限。
  • 在 DROP USER 语句的使用中,若没有明确地给出账户的主机名,则该主机名默认为“%”。

注意:用户的删除不会影响他们之前所创建的表、索引或其他数据库对象,因为 MySQL 并不会记录是谁创建了这些对象。

实例:使用 DROP USER 语句删除用户’S_numb’@‘localhost’。输入的 SQL 语句和执行过程如下所示。

mysql> DROP USER 'S_numb'@'localhost';
Query OK, 0 rows affected (0.00 sec)

在 Windows 命令行工具中,使用 jack 和密码 lion 登录数据库服务器,发现登录失败,说明用户已经删除,如下所示。

C:\Windows\system32>mysql -h localhost -u S_numb -p111111
ERROR 1045 (28000): Access denied for user 'S_numb'@'localhost' (using  password: YES)

9.4 用户授权

当成功创建用户账户后,还不能执行任何操作,需要为该用户分配适当的访问权限。可以使用 SHOW GRANT FOR 语句来查询用户的权限。

注意:新创建的用户只有登录 MySQL 服务器的权限,没有任何其他权限,不能进行其他操作。

USAGE ON*.* 表示该用户对任何数据库和任何表都没有权限。

1. 授予用户权限

对于新建的 MySQL 用户,必须给它授权,可以用 GRANT 语句来实现对新建用户的授权。

语法格式:

GRANT
<权限类型> [ ( <列名> ) ] [ , <权限类型> [ ( <列名> ) ] ]
ON <对象> <权限级别> TO <用户>
其中<用户>的格式:
<用户名> [ IDENTIFIED ] BY [ PASSWORD ] <口令>
[ WITH GRANT OPTION]
| MAX_QUERIES_PER_HOUR <次数>
| MAX_UPDATES_PER_HOUR <次数>
| MAX_CONNECTIONS_PER_HOUR <次数>
| MAX_USER_CONNECTIONS <次数>

语法说明如下:

1) <列名>

可选项。用于指定权限要授予给表中哪些具体的列。

2) ON 子句

用于指定权限授予的对象和级别,如在 ON 关键字后面给出要授予权限的数据库名或表名等。

3) <权限级别>

用于指定权限的级别。可以授予的权限有如下几组:

  • 列权限,和表中的一个具体列相关。例如,可以使用 UPDATE 语句更新表 students 中 student_name 列的值的权限。
  • 表权限,和一个具体表中的所有数据相关。例如,可以使用 SELECT 语句查询表 students 的所有数据的权限。
  • 数据库权限,和一个具体的数据库中的所有表相关。例如,可以在已有的数据库 mytest 中创建新表的权限。
  • 用户权限,和 MySQL 中所有的数据库相关。例如,可以删除已有的数据库或者创建一个新的数据库的权限。

对应地,在 GRANT 语句中可用于指定权限级别的值有以下几类格式:

  • *:表示当前数据库中的所有表。
  • .:表示所有数据库中的所有表。
  • db_name.*:表示某个数据库中的所有表,db_name 指定数据库名。
  • db_name.tbl_name:表示某个数据库中的某个表或视图,db_name 指定数据库名,tbl_name 指定表名或视图名。
  • tbl_name:表示某个表或视图,tbl_name 指定表名或视图名。
  • db_name.routine_name:表示某个数据库中的某个存储过程或函数,routine_name 指定存储过程名或函数名。
  • TO 子句:用来设定用户口令,以及指定被赋予权限的用户 user。若在 TO 子句中给系统中存在的用户指定口令,则新密码会将原密码覆盖;如果权限被授予给一个不存在的用户,MySQL 会自动执行一条 CREATE USER 语句来创建这个用户,但同时必须为该用户指定口令。

2. GRANT语句中的<权限类型>的使用说明如下:

1) 授予数据库权限时,<权限类型>可以指定为以下值:

  • SELECT:表示授予用户可以使用 SELECT 语句访问特定数据库中所有表和视图的权限。
  • INSERT:表示授予用户可以使用 INSERT 语句向特定数据库中所有表添加数据行的权限。
  • DELETE:表示授予用户可以使用 DELETE 语句删除特定数据库中所有表的数据行的权限。
  • UPDATE:表示授予用户可以使用 UPDATE 语句更新特定数据库中所有数据表的值的权限。
  • REFERENCES:表示授予用户可以创建指向特定的数据库中的表外键的权限。
  • CREATE:表示授权用户可以使用 CREATE TABLE 语句在特定数据库中创建新表的权限。
  • ALTER:表示授予用户可以使用 ALTER TABLE 语句修改特定数据库中所有数据表的权限。
  • SHOW VIEW:表示授予用户可以查看特定数据库中已有视图的视图定义的权限。
  • CREATE ROUTINE:表示授予用户可以为特定的数据库创建存储过程和存储函数的权限。
  • ALTER ROUTINE:表示授予用户可以更新和删除数据库中已有的存储过程和存储函数的权限。
  • INDEX:表示授予用户可以在特定数据库中的所有数据表上定义和删除索引的权限。
  • DROP:表示授予用户可以删除特定数据库中所有表和视图的权限。
  • CREATE TEMPORARY TABLES:表示授予用户可以在特定数据库中创建临时表的权限。
  • CREATE VIEW:表示授予用户可以在特定数据库中创建新的视图的权限。
  • EXECUTE ROUTINE:表示授予用户可以调用特定数据库的存储过程和存储函数的权限。
  • LOCK TABLES:表示授予用户可以锁定特定数据库的已有数据表的权限。
  • ALL 或 ALL PRIVILEGES:表示以上所有权限。

2) 授予表权限时,<权限类型>可以指定为以下值:

  • SELECT:授予用户可以使用 SELECT 语句进行访问特定表的权限。
  • INSERT:授予用户可以使用 INSERT 语句向一个特定表中添加数据行的权限。
  • DELETE:授予用户可以使用 DELETE 语句从一个特定表中删除数据行的权限。
  • DROP:授予用户可以删除数据表的权限。
  • UPDATE:授予用户可以使用 UPDATE 语句更新特定数据表的权限。
  • ALTER:授予用户可以使用 ALTER TABLE 语句修改数据表的权限。
  • REFERENCES:授予用户可以创建一个外键来参照特定数据表的权限。
  • CREATE:授予用户可以使用特定的名字创建一个数据表的权限。
  • INDEX:授予用户可以在表上定义索引的权限。
  • ALL 或 ALL PRIVILEGES:所有的权限名。

3) 授予列权限时,<权限类型>的值只能指定为 SELECT、INSERT 和 UPDATE,同时权限的后面需要加上列名列表 column-list。

4) 最有效率的权限是用户权限。

授予用户权限时,<权限类型>除了可以指定为授予数据库权限时的所有值之外,还可以是下面这些值:

  • CREATE USER:表示授予用户可以创建和删除新用户的权限。
  • SHOW DATABASES:表示授予用户可以使用 SHOW DATABASES 语句查看所有已有的数据库的定义的权限。

实例:使用 GRANT 语句创建一个新的用户 sd,密码为 1234。用户 sd 对所有的数据有查询、插入权限,并授予 GRANT 权限。输入的 SQL 语句和执行过程如下所示。

mysql> GRANT SELECT, INSERT ON *.*
    -> TO 'sd'@'localhost'
    -> IDENTIFIED BY '1234'
    -> WITH GRANT OPTION;
Query OK, 0 rows affected, 1 warning (0.01 sec)

使用 SELECT 语句查询用户 sd 的权限,如下所示。

mysql> SELECT Host, User, Select_priv, Grant_priv
    -> FROM mysql.user
    -> WHERE User = 'sd';
+-----------+------+-------------+------------+
| Host      | User | Select_priv | Grant_priv |
+-----------+------+-------------+------------+
| localhost | sd   | Y           | Y          |
+-----------+------+-------------+------------+
1 row in set (0.00 sec)

9.5 删除用户权限

MySQL 数据库中可以使用 REVOKE 语句删除一个用户的权限,此用户不会被删除。

语法格式有两种形式,如下所示:

1. 第一种:

REVOKE <权限类型> [ ( <列名> ) ] [ , <权限类型> [ ( <列名> ) ] ]ON <对象类型> <权限名> FROM <用户1> [ , <用户2> ]

2. 第二种:

REVOKE ALL PRIVILEGES, GRANT OPTION 
FROM user <用户1> [ , <用户2> ]

语法说明如下:

  • REVOKE 语法和 GRANT 语句的语法格式相似,但具有相反的效果。
  • 第一种语法格式用于回收某些特定的权限。
  • 第二种语法格式用于回收特定用户的所有权限。
  • 要使用 REVOKE 语句,必须拥有 MySQL 数据库的全局 CREATE USER 权限或 UPDATE 权限。

实例:使用 REVOKE 语句取消用户 sd 的插入权限,输入的 SQL 语句和执行过程如下所示。

mysql> REVOKE INSERT ON *.*
    -> FROM 'sd'@'localhost';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT Host, User, Select_priv, Insert_priv, Grant_priv
    -> FROM mysql.user
    -> WHERE User = 'sd';
+-----------+------+-------------+-------------+------------+
| Host      | User | Select_priv | Insert_priv | Grant_priv |
+-----------+------+-------------+-------------+------------+
| localhost | sd   | Y           | N           | Y          |
+-----------+------+-------------+-------------+------------+
1 row in set (0.00 sec)

10. 事务

MySQL 数据库中事务是用户一系列的数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位。

1. 为什么要使用事务

事务具有 4 个特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持续性(Durability)。这 4 个特性简称为 ACID 特性。

1) 原子性

事务必须是原子工作单元,事务中的操作要么全部执行,要么全都不执行,不能只完成部分操作。原子性在数据库系统中,由恢复机制来实现。

2) 一致性

事务开始之前,数据库处于一致性的状态;事务结束后,数据库必须仍处于一致性状态。数据库一致性的定义是由用户负责的。例如,在银行转账中,用户可以定义转账前后两个账户金额之和保持不变。

3) 隔离性

系统必须保证事务不受其他并发执行事务的影响,即当多个事务同时运行时,各事务之间相互隔离,不可互相干扰。事务查看数据时所处的状态,要么是另一个并发事务修改它之前的状态,要么是另一个并发事务修改它之后的状态,事务不会查看中间状态的数据。隔离性通过系统的并发控制机制实现。

4) 持久性

一个已完成的事务对数据所做的任何变动在系统中是永久有效的,即使该事务产生的修改不正确,错误也将一直保持。持久性通过恢复机制实现,发生故障时,可以通过日志等手段恢复数据库信息。

事务的 ACID 原则保证了一个事务或者成功提交,或者失败回滚,二者必居其一。因此,它对事务的修改具有可恢复性。即当事务失败时,它对数据的修改都会恢复到该事务执行前的状态。

2. 开始事务

事务以 BEGIN TRANSACTION 开始。

语法格式如下:

 BEGIN TRANSACTION <事务名称> |@<事务变量名称>

语法说明如下:

  • @<事务变量名称>是由用户定义的变量,必须用 char、varchar、nchar 或 nvarchar数据类型来声明该变量。
  • BEGIN TRANSACTION 语句的执行使全局变量 @@TRANCOUNT 的值加 1。

3. 提交事务

COMMIT 表示提交事务,即提交事务的所有操作。具体地说,就是将事务中所有对数据库的更新写回到磁盘上的物理数据库中,事务正常结束。

提交事务,意味着将事务开始以来所执行的所有数据修改成为数据库的永久部分,因此也标志着一个事务的结束。一旦执行了该命令,将不能回滚事务。只有在所有修改都准备好提交给数据库时,才执行这一操作。

语法格式如下:

 COMMIT TRANSACTION <事务名称> |@<事务变量名称>

其中:COMMIT TRANSACTION语句的执行使全局变量 @@TRANCOUNT 的值减 1。

4. 撤销事务

ROLLBACK 表示撤销事务,即在事务运行的过程中发生了某种故障,事务不能继续执行,系统将事务中对数据库的所有已完成的操作全部撤销,回滚到事务开始时的状态。这里的操作指对数据库的更新操作。

当事务执行过程中遇到错误时,使用 ROLLBACK TRANSACTION 语句使事务回滚到起点或指定的保持点处。同时,系统将清除自事务起点或到某个保存点所做的所有的数据修改,并且释放由事务控制的资源。因此,这条语句也标志着事务的结束。

语法格式如下:

ROLLBACK [TRANSACTION]
[<事务名称>| @<事务变量名称> | <存储点名称>| @ <含有存储点名称的变量名>

语法说明如下:

  • 当条件回滚只影响事务的一部分时,事务不需要全部撤销已执行的操作。可以让事务回滚到指定位置,此时,需要在事务中设定保存点(SAVEPOINT)。保存点所在位置之前的事务语句不用回滚,即保存点之前的操作被视为有效的。保存点的创建通过“SAVING TRANSACTION<保存点名称>”语句来实现,再执行“ROLLBACK TRANSACTION<保存点名称>”语句回滚到该保存点。
  • 若事务回滚到起点,则全局变量 @@TRANCOUNT 的值减 1;若事务回滚到指定的保存点,则全局变量 @@TRANCOUNT 的值不变。

5. 案例

1) 执行事务

-- MySQL 是默认开启事务自动提交的
SET autocommit = 0 -- 关闭
SET autocommit = 1 -- 开启(默认的)

-- 手动处理事务
SET autocommit = 0 -- 关闭自动提交

-- 事务开启
START TRANSACTION -- 标记一个事务的开始,从这个之后的 sql 都在同一个事务内

-- 提交:持久化(成功!)
COMMIT

-- 回滚:回到原来的样子(失败!)
ROLLBACK 

-- 事务结束
SET autocommit = 1 -- 开启自动提交

2) 模拟场景

-- 转账
CREATE DATABASE shop CHARACTER SET utf8_general_ci
USE shop

CREATE TABLE `account`(
	`id` INT(3) NOT NULL AUTO_INCREMENT,
	`name` VARCHAR(30) NOT NULL,
	`money` DECIMAL(9, 2) NOT NULL,
	PRIMARY KEY(`id`)
)ENGINE = INNODB DEFAULT CHARSET = utf8

INSERT INTO account(`name`, `money`)
VALUES('A', 2000.00), ('B', 10000.00)

-- 模拟转账:事务
SET autocommit = 0;   -- 关闭自动提交
START TRANSACTION  --  开启一个事务(一组事务)

UPDATE account SET money = monet - 500 WHERE `name` = 'A'  -- A 减 500
UPDATE account SET money = monet + 500 WHERE `name` = 'B'  -- B 加 500

COMMIT; -- 提交事务,就被持久化了
rollback-- 回滚

SET autocommit = 1-- 恢复默认值

11. 数据库备份与恢复

11.1 数据库备份

MySQL 数据库管理系统通常会采用有效的措施来维护数据库的可靠性和完整性。但是在数据库的实际使用过程当中,仍存在着一些不可预估的因素,会造成数据库运行事务的异常中断,从而影响数据的正确性,甚至会破坏数据库,导致数据库中的数据部分或全部丢失。

数据库系统提供了备份和恢复策略来保证数据库中数据的可靠性和完整性。

数据库备份是指通过导出数据或者复制表文件的方式来制作数据库的副本。当数据库出现故障或遭到破坏时,将备份的数据库加载到系统,从而使数据库从错误状态恢复到备份时的正确状态。

可以使用 SELECT INTO OUTFILE 语句把表数据导出到一个文本文件中进行备份。

注意:这种方法只能导出或导入数据的内容,而不包括表的结构。若表的结构文件损坏,则必须先设法恢复原来表的结构。

实例:将数据库 school 的表 student 的全部数据备份到 C 盘的数据备份目录下文件名为 file.txt 的文件中,要求每个字段用逗号分开,并且字符用双引号标注,每行以问号结束。

输入的SQL语句和执行结果如下所示。

mysql> SELECT * FROM school.student
    -> INTO OUTFILE 'C:/Users/76006/Desktop/file.txt'
    -> FIELDS TERMINATED BY '"'
    -> LINES TERMINATED BY '?';
Query OK, 8 rows affected (0.01 sec)

用记事本查看 MySQL 备份文件夹下的 file.txt 文件,内容如下图所示。

MySQL_第15张图片
注:

将数据库中的文件导出到 txt 文件,会报错:

ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement

出错原因:

出现这个问题的原因是 mysql 的 secure_file_priv 这个选项没有开启,或者这个选择了特定的文件路径,只有在这个路径下的文件才能导入导出 mysql。

解决办法:

在 mysql 安装包下的 my.ini 文件添加:
MySQL_第16张图片

然后重启 mysql 服务;

11.2 数据库恢复

数据库恢复是指以备份为基础,与备份相对应的系统维护和管理操作。

系统进行恢复操作时,先执行一些系统安全性的检查,包括检查所要恢复的数据库是否存在、数据库是否变化及数据库文件是否兼容等,然后根据所采用的数据库备份类型采取相应的恢复措施。

数据库恢复机制设计的两个关键问题是:第一,如何建立冗余数据;第二,如何利用这些冗余数据实施数据库恢复。

建立冗余数据最常用的技术是数据转储和登录日志文件。通常在一个数据库系统中,这两种方法是一起使用的。

数据转储是 DBA 定期地将整个数据库复制到磁带或另一个磁盘上保存起来的过程。这些备用的版本成为后备副本或后援副本。

可使用 LOAD DATA…INFILE 语句来恢复先前备份的数据。

实例:将之前导出的数据备份文件 file.txt 导入数据库 school 的表 students_copy 中,其中 students_copy 的表结构和 students 相同。

首先创建表 students_copy,输入的 SQL 语句和执行结果如下所示。

mysql> CREATE TABLE student_copy
    -> LIKE student;
Query OK, 0 rows affected (0.94 sec)

mysql> SELECT * FROM student_copy;
Empty set (0.00 sec)

导入数据与查询表 students_copy 的过程如下所示。

mysql> LOAD DATA INFILE 'C:/Users/76006/Desktop/file.txt'
    -> INTO TABLE school.student_copy
    -> FIELDS TERMINATED BY ','
    -> OPTIONALLY ENCLOSED BY '"'
    -> LINES TERMINATED BY '?';
Query OK, 10 rows affected (0.14 sec)
Records: 8  Deleted: 0  Skipped: 0  Warnings: 0

mysql> SELECT * FROM school.student_copy;
+----+--------+----------+-----+------+---------------------+----------+-------------+
| id | name   | pwd      | sex | age  | birthday            | address  | email       |
+----+--------+----------+-----+------+---------------------+----------+-------------+
| 1  | 张三   | 123456   ||   10 | 2010-07-14 19:56:04 | 北京     | 1234@qq.com |
| 2  | 李四   | 123456   ||    0 | 2020-01-07 19:56:51 | 陕西西安 | 1234@qq.com |
| 3  | Green  | 111111   ||    1 | 2019-03-13 19:57:18 | 北京     | 1234@qq.com |
| 4  | Jim    | 123456   ||    5 | 2015-05-15 19:57:52 | 芝加哥   | 1234@qq.com |
| 5  | John   | 123456   ||   39 | 1981-01-23 19:58:20 | 北京     | 1234@qq.com |
| 6  | Tom    | 12312124 ||    9 | 2011-07-13 19:58:43 | 莫斯科   | 1234@qq.com |
| 7  | 王五   | 123456   ||   20 | 2000-06-15 19:59:08 | 浙江     | 1234@qq.com |
| 8  | 零零七 | 123456   || NULL | NULL                | NULL     | NULL        |
+----+--------+----------+-----+------+---------------------+----------+-------------+
10 rows in set (0.00 sec)

你可能感兴趣的:(MySQL)