1、SQL简介

对数据库进行查询和修改操作的语言叫做 SQL(Structured Query Language,结构化查询语言)。SQL 语言是目前广泛使用的关系数据库标准语言,是各种数据库交互方式的基础。著名的大型商用数据库 Oracle、DB2、Sybase、SQL Server,开源的数据库 PostgreSQL、MySQL,甚至一些小型的数据库 Access 等都支持 SQL。近些年蓬勃发展的 NoSQL 系统最初是宣称不再需要 SQL 的,后来也不得不修正为 Not Only SQL,来拥抱 SQL。

1、SQL是什么

SQL 是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统。与其他程序设计语言(如 C语言、Java 等)不同的是,SQL 由很少的关键字组成,每个 SQL 语句通过一个或多个关键字构成。

  • SQL 具有如下优点:
    1. 一体化:SQL 集数据定义、数据操作和数据控制于一体,可以完成数据库中的全部工作。
    2. 使用方式灵活:SQL 具有两种使用方式,可以直接以命令方式交互使用;也可以嵌入使用,嵌入C、C++、Fortran、COBOL、Java 等语言中使用。
    3. 非过程化:只提操作要求,不必描述操作步骤,也不需要导航。使用时只需要告诉计算机“做什么”,而不需要告诉它“怎么做”,存储路径的选择和操作的执行由数据库管理系统自动完成。
    4. 语言简洁、语法简单:该语言的语句都是由描述性很强的英语单词组成,而且这些单词的数目不多。

image.png

1)数据定义语言(Data Definition Language,DDL)

用来创建或删除数据库以及表等对象,主要包含以下几种命令:

  • DROP:删除数据库和表等对象
  • CREATE:创建数据库和表等对象
  • ALTER:修改数据库和表等对象的结构

    2)数据操作语言(Data Manipulation Language,DML)

    用来变更表中的记录,主要包含以下几种命令:

  • SELECT:查询表中的数据

  • INSERT:向表中插入新数据
  • UPDATE:更新表中的数据
  • DELETE:删除表中的数据

    3)数据查询语言(Data Query Language,DQL)

    用来查询表中的记录,主要包含 SELECT 命令,来查询表中的数据。

4)数据控制语言(Data Control Language,DCL)

用来确认或者取消对数据库中的数据进行的变更。除此之外,还可以对数据库中的用户设定权限。主要包含以下几种命令:

  • GRANT:赋予用户操作权限
  • REVOKE:取消用户的操作权限
  • COMMIT:确认对数据库中的数据进行的变更
  • ROLLBACK:取消对数据库中的数据进行的变更

标准 SQL 是指符合国际标准的 SQL,而非某个数据库厂商的 SQL 语法(如:Microsoft SQL Server 的 T-SQL,Oracle 的 PL/SQL,MySQL)。
标准 SQL 可以在任何数据库中使用,而数据库厂商的 SQL 只适合它们对应的数据库,如 T-SQL 只适合 Microsoft SQL Server。

2、SQL的基本规则

对于 SQL 初学者,在写 SQL 语句时,只要遵守下面几个书写规则,就可以避免很多错误。这些规则都非常简单,下面我们来逐一介绍。

1)SQL 语句要以分号(;)或\G结尾

在 RDBMS (关系型数据库)当中,SQL 语句是逐条执行的,一条 SQL 语句代表着数据库的一个操作。我们通常在句子的句尾加注标点表示这句话结束,中文句子以句号。结尾,英文以点号.结尾,而 SQL 语句则使用英文分号;结尾。

2)SQL 语句不区分大小写

SQL 不区分关键字的大小写。例如,不管写成 SELECT 还是 select,解释都是一样的。表名和列名也是如此。

提示:关键字是数据库事先定义的,有特别意义的单词。
虽然可以根据个人喜好选择大写还是小写(或大小写混杂),但为了理解起来更加容易。

  • 关键字大写
  • 数据库名、表名和列名等小写


需要注意的是,插入到表中的数据是区分大小写的。例如,向数据库中插入单词 Computer、COMPUTER 或 computer,这三个是不一样的数据。

3)SQL的注释

SQL语言的注释是:—

  1. mysql> -- show databases;
  2. mysql> show databases;
  3. +--------------------+
  4. | Database |
  5. +--------------------+
  6. | information_schema |
  7. | mysql |
  8. | performance_schema |
  9. | sys |
  10. +--------------------+
  11. 4 rows in set (0.00 sec)

2、MySQL数据库

在SQL语言中,数据库相当于文件夹。

1、查看数据库

  • 查看所有数据库 ```bash mysql> show databases; +——————————+ | Database | +——————————+ | information_schema | | mysql | | performance_schema | | sys | | test | +——————————+ 7 rows in set (0.00 sec)

mysql>


- 查看数据库定义
```bash
mysql> show create database test01;
+----------+-------------------------------------------------------------------+
| Database | Create Database                                                   |
+----------+-------------------------------------------------------------------+
| test01   | CREATE DATABASE `test01` /*!40100 DEFAULT CHARACTER SET latin1 */ |
+----------+-------------------------------------------------------------------+
1 row in set (0.00 sec)
  • 查看正在使用的数据库 ```sql mysql> use mysql; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A

Database changed mysql> select database(); +——————+ | database() | +——————+ | mysql | +——————+ 1 row in set (0.00 sec)

<a name="l8by4"></a>
### 2、创建数据库

- 释义
   - <数据库名>:创建数据库的名称。MySQL 的数据存储区将以目录方式表示 MySQL 数据库,因此数据库名称必须符合操作系统的文件夹命名规则,不能以数字开头,尽量要有实际意义。注意在 MySQL 中不区分大小写。
   - IF NOT EXISTS:在创建数据库之前进行判断,只有该数据库目前尚不存在时才能执行操作。此选项可以用来避免数据库已经存在而重复创建的错误。
   - [DEFAULT] CHARACTER SET:指定数据库的字符集。指定字符集的目的是为了避免在数据库中存储的数据出现乱码的情况。如果在创建数据库时不指定字符集,那么就使用系统的默认字符集。
   - [DEFAULT] COLLATE:指定字符集的默认校对规则。

- 格式
```sql
CREATE DATABASE [IF NOT EXISTS] <数据库名>
    [[DEFAULT] CHARACTER SET <字符集名>] 
    [[DEFAULT] COLLATE <校对规则名>];
  • 案例 ```sql mysql> CREATE DATABASE IF NOT EXISTS test01 CHARACTER SET utf8 COLLATE utf8_general_ci; Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> show databases; +——————————+ | Database | +——————————+ | information_schema | | db1 | | mysql | | performance_schema | | sys | | test | | test01 | +——————————+ 7 rows in set (0.00 sec)

<a name="pVVDy"></a>
### 3、修改数据库
在 MySQL 数据库中只能对数据库使用的字符集和校对规则进行修改,数据库的这些特性都储存在 db.opt 文件中。下面我们来介绍一下修改数据库的基本操作。
> 注:字符集和校验规则是存储数据库的一种方式。

在 MySQL 中,可以使用 ALTER DATABASE 来修改已经被创建或者存在的数据库的相关参数。修改数据库的语法格式为:
```sql
ALTER DATABASE [数据库名] { 
[ DEFAULT ] CHARACTER SET <字符集名> |
[ DEFAULT ] COLLATE <校对规则名>}
  • 语法说明如下:
    • ALTER DATABASE 用于更改数据库的全局特性。
    • 使用 ALTER DATABASE 需要获得数据库 ALTER 权限。
    • 数据库名称可以忽略,此时语句对应于默认数据库(最新指定数据库)。
    • CHARACTER SET 子句用于更改默认的数据库字符集。
  • 案例 ``bash mysql> show create database test01; +----------+-------------------------------------------------------------------+ | Database | Create Database | +----------+-------------------------------------------------------------------+ | test01 | CREATE DATABASEtest01` /!40100 DEFAULT CHARACTER SET latin1 / | +—————+—————————————————————————————————-+ 1 row in set (0.00 sec)

mysql> ALTER DATABASE test01 -> DEFAULT CHARACTER SET utf8 -> DEFAULT COLLATE utf8_general_ci; Query OK, 1 row affected (0.00 sec)

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

<a name="OBnE3"></a>
### 4、指定数据库
在 MySQL 中就有很多系统自带的数据库,那么在操作数据库之前就必须要确定是哪一个数据库。在 MySQL 中,**USE** 语句用来完成一个数据库到另一个数据库的跳转。

当用 CREATE DATABASE 语句创建数据库之后,该数据库不会自动成为当前数据库,需要用 USE 来指定当前数据库。其语法格式为:
```sql
USE [数据库名称];

注:该语句可以通知 MySQL 把<数据库名>所指示的数据库作为当前数据库。该数据库保持为默认数据库,直到语段的结尾,或者直到遇见一个不同的 USE 语句。 只有使用 USE 语句来指定某个数据库作为当前数据库之后,才能对该数据库及其存储的数据对象执行操作。
  • 案例
    mysql> use test01;
    Database changed
    mysql>
    

5、删除数据库

当数据库不再使用时应该将其删除,以确保数据库存储空间中存放的是有效数据。删除数据库是将已经存在的数据库从磁盘空间上清除,清除之后,数据库中的所有数据也将一同被删除。

在 MySQL 中,当需要删除已创建的数据库时,可以使用 DROP DATABASE 语句。其语法格式为:

DROP DATABASE [ IF EXISTS ] <数据库名>
  • 语法说明如下:

    • <数据库名>:指定要删除的数据库名。
    • IF EXISTS:用于防止当数据库不存在时发生错误。
    • DROP DATABASE:删除数据库中的所有表格并同时删除数据库。使用此语句时要非常小心,以免错误删除。如果要使用 DROP DATABASE,需要获得数据库 DROP 权限。
  • 案例 ```bash mysql> show databases; +——————————+ | Database | +——————————+ | information_schema | | db1 | | mysql | | performance_schema | | sys | | test | | test01 | +——————————+ 7 rows in set (0.00 sec)

mysql> drop database test01; Query OK, 0 rows affected (0.03 sec)

mysql> show databases; +——————————+ | Database | +——————————+ | information_schema | | db1 | | mysql | | performance_schema | | sys | | test | +——————————+ 6 rows in set (0.00 sec)


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

<a name="dTkHK"></a>
### 6、数据库注释

1) 单行注释可以使用#注释符,#注释符后直接加注释内容。格式如下:

注释内容

单行注释使用注释符#的示例如下:

从结果中删除重复行

SELECT DISTINCT product_id, purchase_price FROM Product;

<br />2) 单行注释可以使用--注释符,--注释符后需要加一个空格,注释才能生效。格式如下:
```bash
-- 注释内容
单行注释使用注释符--的示例如下:
-- 从结果中删除重复行
SELECT DISTINCT product_id, purchase_price FROM Product;

和—的区别就是:#后面直接加注释内容,而—的第 2 个破折号后需要跟一个空格符在加注释内容。

3) MySQL 多行注释
多行注释使用/ /注释符。/用于注释内容的开头,/用于注释内容的结尾。多行注释格式如下:

/*
第一行注释内容
第二行注释内容
*/

注释内容写在//之间,可以跨多行。

5、数据表约束(索引约束和数据类型约束)

数据表的约束,从字段名字上可以知道,它是为了控制数据而生的.。

1、主键索引约束

所谓的主键约束就是在数据表中(一般是id字段),选择一个字段充当索引角色。强烈建议一个表中至少要有一个主键索引约束。下面我们介绍主键索引:

主键是一个字段的类型,不能够单独的存在。

创建一个具有主键索引的数据表:

mysql> -- 创建一个具有主键索引的数据表
mysql> CREATE TABLE IF NOT EXISTS pm1(
    ->   id int PRIMARY KEY,
    ->   name VARCHAR(20)
    -> );
Query OK, 0 rows affected (0.01 sec)
mysql> SHOW CREATE TABLE pm1\G
*************************** 1. row ***************************
       Table: pm1
Create Table: CREATE TABLE `pm1` (
  `id` int(11) NOT NULL,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.01 sec)

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

我们尝试插入数据,看看有什么区别?

mysql> -- 插入数据
mysql> INSERT INTO pm1 (id, name) VALUES (1, '小仙女'),(2,"小帅哥");
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM pm1;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | 小仙女    |
|  2 | 小帅哥    |
+----+-----------+
2 rows in set (0.00 sec)

-- 我们可以看到插入数据和查询数据没有什么区别,不急,将上述插入数据的SQL语句重新执行一遍
mysql> INSERT INTO pm1 (id, name) VALUES (1, '小仙女'),(2,"小帅哥");
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

一旦字段被标记成立主键,则其值是无法重复的。除此之外,主键算是MySQL中最快的索引之一。具体的底层算法,我们将在后面的存储引擎原理中详细介绍。

1、自增长
在日常使用数据库的时候常常不知道当天数据的主键索引的编号属于哪一个,这个时候我们就很需要一个自动为我们填充主键编号的功能即为:自增长。

案例:自动填充主键

mysql> -- 创建一个具有主键索引的数据表
mysql> CREATE TABLE IF NOT EXISTS pm2(
    ->   id int PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20)
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> SHOW CREATE TABLE pm2\G
*************************** 1. row ***************************
       Table: pm2
Create Table: CREATE TABLE `pm2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> DESC pm2;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

创建完成数据表之后,填充数据时不增加id,看结果。

mysql> INSERT INTO pm2 (name) VALUES ( '小仙女'),("小帅哥");
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM pm2;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | 小仙女    |
|  2 | 小帅哥    |
+----+-----------+
2 rows in set (0.00 sec)

除此之外,我们还可以设置自动增长的起始值

mysql> -- 创建一个具有主键索引的数据表
mysql> CREATE TABLE IF NOT EXISTS pm3(
    ->   id int PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20)
    -> ) ENGINE=INNODB AUTO_INCREMENT=10000;
Query OK, 0 rows affected (0.03 sec)

mysql> DESC pm3;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> INSERT INTO pm3 (name) VALUES ( '小仙女'),("小帅哥");
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM pm3;
+-------+-----------+
| id    | name      |
+-------+-----------+
| 10000 | 小仙女    |
| 10001 | 小帅哥    |
+-------+-----------+
2 rows in set (0.00 sec)


2、添加主键

当数据表已经创建完毕了,我们需要为该表添加主键,如何添加呢?
格式:

ALTER TABLE <数据表> ADD PRIMARY KEY(字段名称);

案例:

mysql> -- 创建一个具有主键索引的数据表
mysql> CREATE TABLE IF NOT EXISTS pm4(
    ->   id int ,
    -> name VARCHAR(20)
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql> DESC pm4;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | YES  |     | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> ALTER TABLE pm4 ADD PRIMARY KEY(id);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

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

2、唯一索引约束

唯一索引约束跟主键索引类似,也是要求不允许重复,但是主键索引一般作用于id, 唯一索引可以作用于所有的字段。同理唯一索引也是依赖于字段,能够单独存在。

格式:

mysql> -- 创建一个具有主键索引的数据表
mysql> CREATE TABLE IF NOT EXISTS pm6(
    ->   id int PRIMARY KEY,
    -> name VARCHAR(20) UNIQUE KEY
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.02 sec)

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

创建之后,可以尝试向其中name字段插入相同的数据,看结果:

mysql> CREATE TABLE IF NOT EXISTS pm6(
    ->   id int PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20) UNIQUE KEY
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO pm6 (name) VALUES ("小仙女");
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO pm6 (name) VALUES ("小仙女");
ERROR 1062 (23000): Duplicate entry '小仙女' for key 'name'

通过上文可以得出,字段一旦加上了唯一索引,则不能够重复。

3、检查索引

检查索引,顾名思义就是通过设置范围,来管控数据。

案例:

mysql> CREATE TABLE IF NOT EXISTS pm7(
    ->   id int PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20) ,
    -> code  tinyint(2) CHECK( code > 100 AND code < 200 )
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW CREATE TABLE pm7\G
*************************** 1. row ***************************
       Table: pm7
Create Table: CREATE TABLE `pm7` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `code` tinyint(2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> INSERT INTO pm7 (name, code) VALUES ("小仙女", 20);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM pm7;
+----+-----------+------+
| id | name      | code |
+----+-----------+------+
|  1 | 小仙女    |   20 |
+----+-----------+------+
1 row in set (0.00 sec)

4、外键索引(不推荐使用)

外键索引顾名思义就是依赖别的表的数据的一种索引,例如:我们寄快递的时候,需要选择地址:上海市青浦区华徐公路999号。

案例:

mysql> CREATE TABLE city(
    ->   id int PRIMARY KEY AUTO_INCREMENT,
    ->   name VARCHAR(20)
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE city2(
    -> id int PRIMARY KEY AUTO_INCREMENT,
    ->   name VARCHAR(20),
    ->      fid int ,
    ->   FOREIGN KEY(fid) REFERENCES city(id)
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> DESC city;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)

mysql> DESC city2;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  |     | NULL    |                |
| fid   | int(11)     | YES  | MUL | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> INSERT INTO city2 (name,fid) VALUES ("青浦区", 1);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`linux13`.`city2`, CONSTRAINT `city2_ibfk_1` FOREIGN KEY (`fid`) REFERENCES `city` (`id`))

mysql> INSERT INTO city (name) VALUES ("上海市");
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO city2 (name,fid) VALUES ("青浦区", 1);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM city;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | 上海市    |
+----+-----------+
1 row in set (0.00 sec)

mysql> SELECT * FROM city2;
+----+-----------+------+
| id | name      | fid  |
+----+-----------+------+
|  2 | 青浦区    |    1 |
+----+-----------+------+
1 row in set (0.00 sec)

city2变依赖于city变数据,当city表中没有相关数据时,则不能够添加数据到city2。

6、增加字段

MySQL 数据表是由行和列构成的,通常把表的“列”称为字段(Field),把表的“行”称为记录(Record)。随着业务的变化,可能需要在已有的表中添加新的字段。

1、在开头位置添加字段

MySQL 默认在表的最后位置添加新字段,如果希望在开头位置(第一列的前面)添加新字段,那么可以使用 FIRST 关键字。

格式:

ALTER TABLE <表名> ADD <新字段名> <数据类型> [约束条件] FIRST;
  • 案例 ```bash mysql> DESC pm7; +———-+——————-+———+——-+————-+————————+ | Field | Type | Null | Key | Default | Extra | +———-+——————-+———+——-+————-+————————+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | YES | | NULL | | | code | tinyint(2) | YES | | NULL | | +———-+——————-+———+——-+————-+————————+ 3 rows in set (0.00 sec)

mysql> ALTER TABLE pm7 ADD address VARCHAR(20) FIRST; Query OK, 0 rows affected (0.03 sec) Records: 0 Duplicates: 0 Warnings: 0

mysql> DESC pm7; +————-+——————-+———+——-+————-+————————+ | Field | Type | Null | Key | Default | Extra | +————-+——————-+———+——-+————-+————————+ | address | varchar(20) | YES | | NULL | | | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | YES | | NULL | | | code | tinyint(2) | YES | | NULL | | +————-+——————-+———+——-+————-+————————+ 4 rows in set (0.00 sec)

<a name="aBxzL"></a>
#### 2、在中间位置添加字段

MySQL 除了允许在表的开头位置和末尾位置添加字段外,还允许在中间位置(指定的字段之后)添加字段,此时需要使用 AFTER 关键字。
```bash
ALTER TABLE <表名> ADD <新字段名> <数据类型> [约束条件] AFTER <已经存在的字段名>;

AFTER 的作用是将新字段添加到某个已有字段后面。

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

mysql> ALTER TABLE db01 ADD sex VARCHAR(20) AFTER id;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> DESC db01;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| name  | varchar(20) | YES  |     | NULL    |                |
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| sex   | varchar(20) | YES  |     | NULL    |                |
| addr  | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

3、在末尾位置添加字段

一个完整的字段包括字段名、数据类型和约束条件。

ALTER TABLE <表名> ADD <新字段名><数据类型>[约束条件];

对语法格式的说明如下:

  • <表名> 为数据表的名字
  • <新字段名> 为所要添加的字段的名字
  • <数据类型> 为所要添加的字段能存储数据的数据类型
  • [约束条件] 是可选的,用来对添加的字段进行约束

使用 ALTER TABLE 语句添加一个 INT 类型的字段 age,SQL 语句和运行结果如下:

mysql> DESC db01;
+-------+---------+------+-----+---------+----------------+
| Field | Type    | Null | Key | Default | Extra          |
+-------+---------+------+-----+---------+----------------+
| id    | int(11) | NO   | PRI | NULL    | auto_increment |
+-------+---------+------+-----+---------+----------------+
1 row in set (0.00 sec)

mysql> ALTER TABLE db01 ADD addr VARCHAR(20);
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> DESC db01;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| addr  | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

4、字段的琐碎内容

将字段中常用的约束一一列举出来。

1、是否允许为空

是否为空顾名思义就是设置是否允许字段为空。其格式是:NOT NULL

案例

mysql> CREATE TABLE IF NOT EXISTS pm8(
    ->   id int PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20) NOT NULL
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE IF NOT EXISTS pm9(
    ->   id int PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20) 
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO pm9 (id) VALUES (10);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO pm8 (id) VALUES (10);
ERROR 1364 (HY000): Field 'name' doesn't have a default value    '

mysql> INSERT INTO pm8 (name) VALUES ( '小仙女');
Query OK, 1 row affected (0.01 sec)

2、默认值

默认值,顾名思义就是给字段设置一个默认值,当字段没有添加任何值的时候,使用默认值进行填充。

案例:

mysql> CREATE TABLE IF NOT EXISTS pm10(
    ->   id int PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20) DEFAULT "小仙女"
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.01 sec)

mysql> DESC pm10;
+-------+-------------+------+-----+-----------+----------------+
| Field | Type        | Null | Key | Default   | Extra          |
+-------+-------------+------+-----+-----------+----------------+
| id    | int(11)     | NO   | PRI | NULL      | auto_increment |
| name  | varchar(20) | YES  |     | 小仙女    |                |
+-------+-------------+------+-----+-----------+----------------+
2 rows in set (0.00 sec)

mysql> INSERT INTO pm10 (id) VALUES (10);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM pm10;
+----+-----------+
| id | name      |
+----+-----------+
| 10 | 小仙女    |
+----+-----------+
1 row in set (0.00 sec)

3、字段注释

字段注释,顾名思义就是给字段一个注释,有利于后期维护的时候快速理解字段含义。
案例:

-- 字段注释
mysql> CREATE TABLE IF NOT EXISTS pm11(
    ->   id int PRIMARY KEY AUTO_INCREMENT COMMENT "主键字段",
    -> name VARCHAR(20) DEFAULT "小仙女" COMMENT "名字"
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.01 sec)

mysql> SHOW CREATE TABLE pm11\G
*************************** 1. row ***************************
       Table: pm11
Create Table: CREATE TABLE `pm11` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键字段',
  `name` varchar(20) DEFAULT '小仙女' COMMENT '名字',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)


-- 表注释
mysql> CREATE TABLE IF NOT EXISTS pm12(
    ->   id int PRIMARY KEY AUTO_INCREMENT COMMENT "主键字段",
    -> name VARCHAR(20) DEFAULT "小仙女" COMMENT "名字"
    -> ) ENGINE=INNODB COMMENT "仙女表";
Query OK, 0 rows affected (0.02 sec)

mysql> SHOW CREATE TABLE pm12\G
*************************** 1. row ***************************
       Table: pm12
Create Table: CREATE TABLE `pm12` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键字段',
  `name` varchar(20) DEFAULT '小仙女' COMMENT '名字',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='仙女表'
1 row in set (0.00 sec)

7、连表查询

两个或多个表至之间通过某种关系,按照某种规则合并起来查询出来的数据即为连表查询,连表查询是企业中常用一种查询数据方式,在关系型数据库中连表查询是很常见的。但是连表查询仅仅限于同一个数据库内多张数据表相互链接,不同数据库中的数据便无法使用连表查询。

1、内连接(INNER JOIN )

把两个数据表中的所有的数据一次性按照某种条件一次性查询出来。

案例

mysql> use linux13;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> 
mysql> CREATE TABLE IF NOT EXISTS student(
    -> id INT PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20) NOT NULL COMMENT "学生名称",
    -> age TINYINT(2) NOT NULL DEFAULT 18 COMMENT "年龄"
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE IF NOT EXISTS major (
    -> id INT PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20) NOT NULL COMMENT "专业名称"
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> CREATE TABLE IF NOT EXISTS student_major(
    -> id INT PRIMARY KEY AUTO_INCREMENT,
    -> stu_id INT NOT NULL COMMENT "学生表ID",
    -> m_id INT NOT NULL COMMENT "专业表ID"
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE IF NOT EXISTS teacher(
    -> id INT PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20) NOT NULL COMMENT "老师名称"
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE IF NOT EXISTS tearch_major(
    -> id INT PRIMARY KEY AUTO_INCREMENT,
    -> tea_id INT NOT NULL COMMENT "老师表ID",
    -> m_id INT NOT NULL COMMENT "专业表ID"
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> INSERT INTO student (name,age) VALUES ("小明", 18),("小红", 17),("小花", 16);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> INSERT INTO major (name) VALUES ("数学"),("英语"),("毛概");
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> INSERT INTO teacher (name) VALUES ("李铁锤"),("石林"),("为李飞");
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * FROM student;
+----+--------+-----+
| id | name   | age |
+----+--------+-----+
|  1 | 小明   |  18 |
|  2 | 小红   |  17 |
|  3 | 小花   |  16 |
+----+--------+-----+
3 rows in set (0.00 sec)

mysql> select * FROM teacher;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | 李铁锤    |
|  2 | 石林      |
|  3 | 为李飞    |
+----+-----------+
3 rows in set (0.00 sec)

mysql> select * FROM major;
+----+--------+
| id | name   |
+----+--------+
|  1 | 数学   |
|  2 | 英语   |
|  3 | 毛概   |
+----+--------+
3 rows in set (0.00 sec)


INSERT INTO student_major (stu_id, m_id) VALUES (1, 1),(1,2);
INSERT INTO student_major (stu_id, m_id) VALUES (2, 1),(2,3);
INSERT INTO student_major (stu_id, m_id) VALUES (3, 1),(3,2),(3,3);

mysql> select * from student_major;
+----+--------+------+
| id | stu_id | m_id |
+----+--------+------+
|  1 |      1 |    1 |
|  2 |      1 |    2 |
|  3 |      2 |    1 |
|  4 |      2 |    3 |
|  5 |      3 |    1 |
|  6 |      3 |    2 |
|  7 |      3 |    3 |
+----+--------+------+
7 rows in set (0.00 sec)


mysql> INSERT INTO tearch_major (tea_id, m_id) VALUES (1,3),(2,1),(3,2);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * FROM tearch_major;
+----+--------+------+
| id | tea_id | m_id |
+----+--------+------+
|  1 |      1 |    3 |
|  2 |      2 |    1 |
|  3 |      3 |    2 |
+----+--------+------+
3 rows in set (0.00 sec)

数据建立完毕之后,我们有如下几个需求:

1、查询出小明选修哪几门课?

-- 按照既学的内容,我们可以得出如下:

mysql> SELECT * FROM student WHERE id = 1;
+----+--------+-----+
| id | name   | age |
+----+--------+-----+
|  1 | 小明   |  18 |
+----+--------+-----+
1 row in set (0.00 sec)

mysql> SELECT * FROM student_major WHERE stu_id = 1;
+----+--------+------+
| id | stu_id | m_id |
+----+--------+------+
|  1 |      1 |    1 |
|  2 |      1 |    2 |
+----+--------+------+
2 rows in set (0.01 sec)

mysql> SELECT * FROM major WHERE id = 1 or id = 2;
+----+--------+
| id | name   |
+----+--------+
|  1 | 数学   |
|  2 | 英语   |
+----+--------+
2 rows in set (0.00 sec)

-- 通过上面可知,如果需要查询出选修的课程需要三步,非常的繁琐,那么我们介绍一下连表查询。
mysql> SELECT * FROM student INNER JOIN  student_major ON student.id = student_major.stu_id WHERE student.id = 1;
+----+--------+-----+----+--------+------+
| id | name   | age | id | stu_id | m_id |
+----+--------+-----+----+--------+------+
|  1 | 小明   |  18 |  1 |      1 |    1 |
|  1 | 小明   |  18 |  2 |      1 |    2 |
+----+--------+-----+----+--------+------+
2 rows in set (0.00 sec)
-- 由上可知,数据库连表查询非常方便快捷。

mysql> SELECT * FROM student INNER JOIN  student_major ON student.id = student_major.stu_id  INNER JOIN major ON student_major.m_id = major.id WHERE student.id = 1;
+----+--------+-----+----+--------+------+----+--------+
| id | name   | age | id | stu_id | m_id | id | name   |
+----+--------+-----+----+--------+------+----+--------+
|  1 | 小明   |  18 |  1 |      1 |    1 |  1 | 数学   |
|  1 | 小明   |  18 |  2 |      1 |    2 |  2 | 英语   |
+----+--------+-----+----+--------+------+----+--------+
2 rows in set (0.00 sec)

-- 由上简化得来
mysql> SELECT student.id,student.name,student.age, major.name FROM student INNER JOIN  student_major ON student.id = student_major.stu_id  INNER JOIN major ON student_major.m_id = major.id WHERE student.id = 1;
+----+--------+-----+--------+
| id | name   | age | name   |
+----+--------+-----+--------+
|  1 | 小明   |  18 | 数学   |
|  1 | 小明   |  18 | 英语   |
+----+--------+-----+--------+
2 rows in set (0.00 sec)

2、查询出小花选修的课的老师有哪些?

mysql> SELECT  student.id,student.name,student.age, major.name,teacher.name  FROM  student  INNER JOIN  student_major ON student.id = student_major.stu_id   INNER JOIN major ON student_major.m_id = major.id  INNER JOIN tearch_major ON tearch_major.m_id = major.id INNER JOIN teacher ON teacher.id =  tearch_major.tea_id WHERE student.id = 3;
+----+--------+-----+--------+-----------+
| id | name   | age | name   | name      |
+----+--------+-----+--------+-----------+
|  3 | 小花   |  16 | 毛概   | 李铁锤    |
|  3 | 小花   |  16 | 数学   | 石林      |
|  3 | 小花   |  16 | 英语   | 为李飞    |
+----+--------+-----+--------+-----------+
3 rows in set (0.00 sec)

2、左连接(LEFT JOIN)

左连接顾名思义就是以左边的表为主表,其他的表为副表;也就是说会把左边表中所有的符合条件的数据全部查询出来,至于后面的表有没有内容不管,没有内容则用空来代替。

案例:

-- 插入一个学生
INSERT INTO student (name, age) VALUES ("铁锤", 18);

SELECT * FROM student LEFT JOIN student_major ON student.id = student_major.stu_id ;
SELECT * FROM student INNER JOIN student_major ON student.id = student_major.stu_id;

mysql> SELECT * FROM student LEFT JOIN student_major ON student.id = student_major.stu_id ;
+----+--------+-----+------+--------+------+
| id | name   | age | id   | stu_id | m_id |
+----+--------+-----+------+--------+------+
|  1 | 小明   |  18 |    1 |      1 |    1 |
|  1 | 小明   |  18 |    2 |      1 |    2 |
|  2 | 小红   |  17 |    3 |      2 |    1 |
|  2 | 小红   |  17 |    4 |      2 |    3 |
|  3 | 小花   |  16 |    5 |      3 |    1 |
|  3 | 小花   |  16 |    6 |      3 |    2 |
|  3 | 小花   |  16 |    7 |      3 |    3 |
|  4 | 铁锤   |  18 | NULL |   NULL | NULL |
+----+--------+-----+------+--------+------+
8 rows in set (0.00 sec)

mysql> SELECT * FROM student INNER JOIN student_major ON student.id = student_major.stu_id;
+----+--------+-----+----+--------+------+
| id | name   | age | id | stu_id | m_id |
+----+--------+-----+----+--------+------+
|  1 | 小明   |  18 |  1 |      1 |    1 |
|  1 | 小明   |  18 |  2 |      1 |    2 |
|  2 | 小红   |  17 |  3 |      2 |    1 |
|  2 | 小红   |  17 |  4 |      2 |    3 |
|  3 | 小花   |  16 |  5 |      3 |    1 |
|  3 | 小花   |  16 |  6 |      3 |    2 |
|  3 | 小花   |  16 |  7 |      3 |    3 |
+----+--------+-----+----+--------+------+
7 rows in set (0.00 sec)

3、右链接(Right JOIN)

右链接顾名思义就是用右边表作为主表,其他表作为副表。也就是说,右链接是会把右边的表中的所有的数据全部都查询出来,至于左边的表如果没有数据既用空代替。

案例:

INSERT INTO student_major (stu_id,m_id) VALUES (4, 5);

mysql> SELECT * FROM  major LEFT JOIN student_major ON major.id = student_major.m_id;
+----+--------+------+--------+------+
| id | name   | id   | stu_id | m_id |
+----+--------+------+--------+------+
|  1 | 数学   |    1 |      1 |    1 |
|  2 | 英语   |    2 |      1 |    2 |
|  1 | 数学   |    3 |      2 |    1 |
|  3 | 毛概   |    4 |      2 |    3 |
|  1 | 数学   |    5 |      3 |    1 |
|  2 | 英语   |    6 |      3 |    2 |
|  3 | 毛概   |    7 |      3 |    3 |
|  4 | Linux  | NULL |   NULL | NULL |
+----+--------+------+--------+------+
8 rows in set (0.00 sec)

mysql> SELECT * FROM  major RIGHT JOIN student_major ON major.id = student_major.m_id;
+------+--------+----+--------+------+
| id   | name   | id | stu_id | m_id |
+------+--------+----+--------+------+
|    1 | 数学   |  1 |      1 |    1 |
|    1 | 数学   |  3 |      2 |    1 |
|    1 | 数学   |  5 |      3 |    1 |
|    2 | 英语   |  2 |      1 |    2 |
|    2 | 英语   |  6 |      3 |    2 |
|    3 | 毛概   |  4 |      2 |    3 |
|    3 | 毛概   |  7 |      3 |    3 |
| NULL | NULL   |  8 |      4 |    5 |
+------+--------+----+--------+------+
8 rows in set (0.00 sec)

mysql> SELECT * FROM  major INNER JOIN student_major ON major.id = student_major.m_id;
+----+--------+----+--------+------+
| id | name   | id | stu_id | m_id |
+----+--------+----+--------+------+
|  1 | 数学   |  1 |      1 |    1 |
|  2 | 英语   |  2 |      1 |    2 |
|  1 | 数学   |  3 |      2 |    1 |
|  3 | 毛概   |  4 |      2 |    3 |
|  1 | 数学   |  5 |      3 |    1 |
|  2 | 英语   |  6 |      3 |    2 |
|  3 | 毛概   |  7 |      3 |    3 |
+----+--------+----+--------+------+
7 rows in set (0.00 sec)

4、合并数据

顾名思义就是将多个SQL语句查询出来的数据合并一次性查询出来。需要注意的是,两边的字段必须一致。
案例:

mysql> SELECT name,age FROM student UNION SELECT * FROM teacher;
+--------+-----------+
| name   | age       |
+--------+-----------+
| 小明   | 18        |
| 小红   | 17        |
| 小花   | 16        |
| 铁锤   | 18        |
| 1      | 李铁锤    |
| 2      | 石林      |
| 3      | 为李飞    |
+--------+-----------+
7 rows in set (0.00 sec)

8、子查询

子查询顾名思义就是在SQL中依赖于另一个SQL语句的结果来共同查询一个结果。每一个子查询语句只能够返回一条数据。在工作用极其不建议使用子查询,因为子查询的性能非常低。
案例:

mysql> SELECT * FROM student WHERE id = (SELECT DISTINCT stu_id FROM student_major LIMIT 1);
+----+--------+-----+
| id | name   | age |
+----+--------+-----+
|  1 | 小明   |  18 |
+----+--------+-----+
1 row in set (0.00 sec)