# lanzhoutbc
**Repository Path**: azureroots/lanzhoutbc
## Basic Information
- **Project Name**: lanzhoutbc
- **Description**: 兰州工商学院数据库实践课程集中实训
- **Primary Language**: SQL
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-11-07
- **Last Updated**: 2025-11-12
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## 1、准备环境
## 2、权限操作
### 2.0、 创建数据库
在 MySQL 5.x 中使用以下语句来创建数据库:
```sql
create database 数据库名 default character set utf8mb4 ;
```
在 MySQL 8.x 中可以将 `default character set utf8mb4` 省略
```sql
create database 数据库名;
```
### 2.1、创建用户
在 MySQL 5.x 中可以通过以下方式创建用户:
```sql
create user 用户名 identified by '密码' ;
```
( 这里注意,密码必须使用引号包起来 )
### 2.2、删除用户
```sql
drop user 用户名 ;
```
### 2.3、修改用户名
```sql
rename user 原用户名 to 新用户名 ;
```
### 2.4、授予权限
```sql
grant 权限名 (columns) on 权限对象 to 用户名@域 [ identified by '密码' ] ;
```
(权限名称 和 权限对象 比较多,参见 《MySQL 技术内幕 第四版》 12.4 )
我们采用以下形式为用户授权:
```sql
grant all on 数据库名称.* to 用户名@域 identified by '密码';
```
例如,假设存在数据库 taobao ,存在用户 malajava ,把 taobao 数据库的所有权限授予 malajava 用户 :
```sql
grant all on taobao.* to malajava@localhost identified by 'malajava' ;
```
### 2.5、查看当前用户
```sql
select user() ;
```
### 2.6、查看用户的权限
```sql
show grants for '用户名'@'域'
```
查看当前用户的权限:
```sql
show grants ;
```
### 2.7、修改 root 用户的密码
第一种方法:
```sql
mysql> set password for 'root'@'localhost' = password('新密码');
```
第二种方法:
```sql
mysql> use mysql ;
mysql> update user set password = password('newpass') where user = 'root';
mysql> flush privileges ;
mysql> PRIVILEGES;
```
## 3、数据库操作
### 3.1、创建数据库
在 MySQL 8 之前,创建数据库时建议使用以下语句:
```sql
create database 数据库名 default character set 字符集编码名称;
```
主要是通过 `default characte set ` 来设置数据库所采用的字符编码方案。
例如:建立一个名为 `lanzhoutbc`的数据库
```sql
create database `lanzhoutbc` ;
```
创建 `lanzhoutbc` 数据库并指定数据库的字符集编码:
```sql
create database `lanzhoutbc` default character set utf8mb4;
```
这里需要注意的是,在 MySQL 使用的 utf8 并不是真正意义上的 `UTF-8` 。
在 MySQL 中使用真正的 `UTF-8` 应该指定为 `utf8mb4` 。
从 MySQL 8 开始,创建数据库时默认就采用了 `utf8mb4` (即 `UTF-8`编码):
```sql
create database lanzhoutbc ;
```
可以通过 `show create database lanzhoutbc` 来查看:
```sql
mysql> show create database lanzhoutbc ;
+----------+------------------------------------------------------------------------------------------------+
| Database | Create Database |
+----------+------------------------------------------------------------------------------------------------+
| lanzhoutbc | CREATE DATABASE `lanzhoutbc` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */|
+----------+------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
```
### 3.2、显示所有的数据库
```sql
show databases
```
对于root用户来说,可以看到所有数据库;
对于非root用户来说,只能看到该用户拥有操作权限的数据库;
### 3.3、删除数据库
```sql
drop database 数据库名 ;
```
例如:删除名为 malajava 的数据库
```sql
drop database malajava ;
```
### 3.4、连接数据库
连接数据库也称作**选择数据库**或打开数据库,采用 use 关键字实现:
```sql
use 数据库名 ;
```
例如:如果 `malajava` 数据库存在,尝试打开它:
```sql
use malajava
```
### 3.5、查看当前数据库
查看当前正在操作的数据库(当前已经选择的数据库)
```sql
select database();
```
以上操作仅在 命令提示符 可以执行。
### 3.6、当前数据库包含的表
```sql
show tables ;
```
注意,必须先选中一个数据库,即先使用 use 打开一个数据库,比如: use malajava ,之后才可以查看该数据库中所包含的表。
### 3.7、查看创建数据库时的相关信息
```sql
show create database 数据库名称 ;
```
## 4、表操作
操作表之前,必须先选中相应的数据库( 使用 `use` 命令,比如 `use malajava` )
### 4.1、创建表
```sql
create table 表名 ( 列名 数据类型(列宽) , ... ) ;
```
比如创建 student 表:
```sql
create table student ( id int primary key , name varchar(20) ) ;
```
### 4.2、查看表结构
语法:
```sql
describe 表名 ;
```
其中,describe 可以缩写为 desc 。
举例(查看 student 表的表结构):
```sql
desc student ;
```
### 4.3、增加列
语法:
```sql
alter table 表名 add column ( 列名 类型 约束 ) ;
```
比如,为 `t_students` 表添加 `address` 列 :
```sql
alter table `t_students` add column ( `address` varchar(50) );
```
### 4.4、修改列
#### 4.4.1 修改列类型
语法:
```sql
alter table 表名 modify 列名 类型(列宽) ;
```
举例(修改 student 表的 address 列的 类型 和 宽度 ):
```sql
alter table `t_students` modify `address` varchar(100) ;
```
#### 4.4.2 修改列名
语法:
```sql
alert table 表名 change column 原列名 新列名 类型 ;
```
举例(将 t_students 表的 address 列名 修改为 hometown ):
```sql
alert table `t_students` change column `address` `hometown` varchar(100) ;
```
### 4.5、删除列
语法:
```sql
alter table 表名 drop column 列名 ;
```
举例 ( 删除 t_students 表中的 hometown 列 ) :
```sql
alter table `t_students` drop column `hometown` ;
```
### 4.6、删除表
语法:
```sql
drop table 表名 ;
```
举例( 删除 t_students 表 ):
```sql
drop table `t_students` ;
```
### 4.7、截断表
语法:
```sql
truncate table 表名 ;
```
举例( 截断 `t_students` 表 ):
```sql
truncate table `t_students` ;
```
### 4.8、重命名表
语法:
```sql
rename table 原表名 to 新表名 ;
```
举例( 将 t_students 重命名为 students ):
```sql
rename table t_students to students ;
```
### 4.9、查看建表时的相关信息
语法:
```sql
show create table 表名 ;
```
举例:
```sql
show create table t_students ;
```
## 5、数据操作
### 5.1、插入数据
语法:
```sql
insert into 表名 ( 列名 , ... ) values ( 数值 , ... ) ;
```
举例:
```sql
insert into t_students ( id , name , gender ) values ( 1 , '张无忌' , '男' ) ;
```
批量插入数据语法:
```sql
insert into 表名 ( 列名 , ... ) values ( 数值 , ... ) , ( 数值 , ... ),( 数值 , ... ) , ... ;
```
举例:
```sql
insert into t_students ( id , name ) values ( 2 , '周芷若' ) , ( 3 , '赵敏' ) ;
```
### 5.2、更新数据
语法:
```sql
update 表名 set 列名 = 取值 , ... [ where 条件 ] ;
```
其中的 where 子句并不是必须的,可以根据实际需要来确定是否需要跟 where 子句。
举例:
```sql
update t_students set name='敏敏特穆尔' , gender = '女' where id = 3 ;
```
注意,如果在 update 语句中没有使用 where 子句筛选,则会更新整张表中的每一行数据。
### 5.3、删除数据
语法:
```sql
delete from 表名 where 条件 ;
```
其中的 where 子句不是必须的,根据实际需要来确定是否需要跟 where 子句。
举例( 删除 t_students 表中 id 为 3 的记录 ):
```sql
delete from t_students where id = 3 ;
```
注意,如果在 delete 语句中没有使用 where 子句筛选,则会删除整张表中的所有数据。
如果要删除一张表中的所有数据,使用 delete from 效率是较低的,建议使用 truncate table 。
## 6、数据查询
### 6.1、数据查询
#### 6.1.1、简单查询
##### (1)、查询部分列
如果需要在查询结果中仅包含表中部分列,可以在 `SELECT` 关键字之后显式书写这些列的列名:
```sql
SELECT deptno, dname FROM dept;
SELECT empno, ename, sal FROM emp;
```
##### (2)、查询全部列
如果需要查询表中所有列,可以在 `SELECT` 之后使用 `*` 来表示所有列:
```sql
SELECT * FROM emp;
SELECT emp.* FROM emp;
```
此处 `*` 就表示所有列。
##### (3)、算术运算
在 SQL 语句中可以通过算术运算符实现运算:
- 求 `emp` 表中所有员工的 年薪
```sql
SELECT empno, ename, sal * 12 FROM emp;
```
- 求 `emp` 表中所有员工的 周薪
```sql
SELECT empno, ename, sal / 4 FROM emp;
```
需要注意的是,MySQL 8.4.x 中允许通过 `%` 和 `mod` 来求模:
```sql
SELECT 5%2, mod(5,2) FROM dual;
```
##### (4)、虚表
从 MySQL 8 开始,允许使用一个名称为 `dual` 的 续表 来辅助查询。
- 执行算术运算
```sql
SELECT mod( 5, 2 ) FROM dual;
```
- 查询时间
```sql
SELECT sysdate(), cureent_date(), current_time(), current_timestamp() FROM dual;
```
- 查询当前数据库
```sql
SELECT database() FROM dual;
```
##### (5)、列的别名
在 `SELECT` 中可以为列指定别名:
```sql
SELECT empno 工号, ename AS 姓名, sal * 12 AS 年薪 FROM emp;
```
为列指定别名时,可以使用 `AS` 关键字,也可以省略。
##### (6)、拼接字符串
在 MySQL 数据库中可以通过 `concat` 函数来拼接字符串。
```sql
select concat(first_name, concat( '·', last_name) ) from s_emp;
```
##### (7)、处理空值
数据库中的空值既不是空字符串,也不是数字0,而是没有值,是未知值。
因此,尽管在插入数据时可以使用 null 来表示该列的值是个空值,但两个都为空的值是不能直接比较的( 判断某个值是否为空需要使用 is null 而不是 x = null )。
因为不能直接比较空值,所以在主流的数据库中都会提供相应的函数来处理空值。
MySQL 数据库中提供了 `ifnull` 函数来处理空值。
- 查询 `emp` 表中所有雇员的工号、姓名、领导编号(若某个员工没有领导则显示`这是老板`)
```sql
SELECT empno, ename , ifnull( manager, '这是老板' ) FROM emp ;
```
##### (8)、去除重复行
去除查询结果中重复的数据行,可以通过 `DISTINCT` 关键字来完成。
- 查询 `emp` 表中所有的部门号 (含重复行)
```sql
SELECT ALL deptno FROM emp;
```
此处的 `ALL` 是默认值,通常是省略的。
- 查询 `emp` 表中所有的部门号 (去除重复行)
```sql
SELECT DISTINCT deptno FROM emp;
```
- 查询 `emp` 表中的 部门 和 岗位 (含重复行)
```sql
SELECT deptno, job FROM emp;
```
此处 `SELECT` 之后并没有显式书写 `ALL` ,因为 `ALL`是默认值,所以效果是一样的。
- 查询 `emp` 表中的 部门 和 岗位 (去除重复行)
```sql
SELECT DISTINCT deptno, job FROM emp;
```
#### 6.1.2、数据过滤
在本节之前所做的所有查询都是没有带任何过滤条件的查询,因此查询结果中包含被查询表中的所有数据行。
如果需要对表中的数据进行筛选,可以使用 SELECT 语句中的 WHERE 子句实现数据过滤,从而只返回那些满足条件的数据行。
其语法格式为:
```sql
SELECT column_name [ , … ]
FROM table_name
WHERE condition_expression ;
```
其中:
- `column_name` 为需要查询的列名
- `table_name` 为被查询表的表名称
- `condition_expression` 是筛选数据时所使用的条件
在WHERE子句指定的条件中,通常需要使用比较运算符、SQL运算符、逻辑运算符。
##### (1)、⽐较运算符
可以在 where 字句后面实用的比较运算符,包括:
| 运算符 | 含义 | 举例 |
| -------- | ---------- | -------------- |
| = | 等于 | deptno = 20 |
| <> 或 != | 不等于 | deptno != 10 |
| < | 小于 | salary > 1500 |
| > | 大于 | salary < 1500 |
| <= | 小于或等于 | salary <= 1500 |
| >= | 大于或等于 | salary >= 1500 |
应用举例:
- 查询 `emp` 表中部门号为 `20` 的雇员信息,列出其工号、姓名、月薪、岗位
```sql
SELECT empno, ename, sal, job FROM emp WHERE deptno = 20 ;
```
- 查询 `emp` 表中月薪高于 1500,低于 3000 的雇员信息,列出其工号、姓名、月薪、岗位
```sql
SELECT empno, ename, sal, job
FROM emp
WHERE sal > 1500 AND sal < 3000 ;
```
- 查询 `emp` 表中月薪不低于 1500,不高于 3000 的雇员信息,列出其工号、姓名、月薪、岗位
```sql
SELECT empno, ename, sal, job
FROM emp
WHERE sal >= 1500 AND sal <= 3000 ;
```
##### (2)、SQL 运算符
使用SQL 运算符可以基于字符串的模式匹配、值的列表、值的范围和是否空值等情况来过滤数据。
MySQL 中常用的 SQL 运算符有:
| 运算符 | 描述 |
| -------------------- | -------------------------------------- |
| like | 按照指定的模式匹配(比如模糊查询) |
| in | 匹配的值的清单 in( list ) |
| between .... and ... | 匹配的值的范围 ( between ... and ... ) |
| is null | 与空值匹配 |
| is nan | 与非数字匹配 ( nan: not a number ) |
应用举例:
- 查询 `emp` 表中月薪不低于 1500,不高于 3000 的雇员信息,列出其工号、姓名、月薪、岗位
```sql
SELECT empno, ename, sal, job
FROM emp
WHERE sal BETWEEN 1500 AND 3000 ;
```
- 查询 `emp` 表中 **提成为空** 的雇员信息,列出其工号、姓名、月薪、岗位、提成
```sql
SELECT empno, ename, sal, job, comm
FROM emp
WHERE comm IS NULL;
```
- 查询 `emp` 表中 **提成不为空** 的雇员信息,列出其工号、姓名、月薪、岗位、提成
```sql
SELECT empno, ename, sal, job, comm
FROM emp
WHERE comm IS NOT NULL;
```
- 查询 `emp` 表中 **没有提成** 的雇员信息,列出其工号、姓名、月薪、岗位、提成
```sql
SELECT empno, ename, sal, job, comm
FROM emp
WHERE comm IS NULL OR comm = 0 ;
```
此处需要注意,**没有提成** 是指 **提成为空** 以及 **提成等于 0** 的两类数据。
- 查询 `emp` 表中 10、20 两个部门的 工号、姓名、岗位、部门号
```sql
SELECT empno, ename, job, deptno
FROM emp
WHERE deptno IN (10, 20);
```
- 查询 `s_emp` 表中 `last_name` 第三个字母是 `a` 的雇员的 `id` 和`last_name`
```sql
SELECT id, last_name
FROM s_emp
WHERE lower(last_name) LIKE '__a%';
```
- 查询 `s_emp` 表中 `last_name` 包含 `_` 的雇员信息
```sql
SELECT id, last_name
FROM s_emp
WHERE lower(last_name) LIKE '%\_%';
```
此处使用 `\` 对 `_` 进行转义。
- 自定义转义字符
```sql
SELECT id, last_name
FROM s_emp
WHERE lower(last_name) LIKE '%\_%' ESCAPE '\' ;
```
##### (3)、逻辑运算符
逻辑运算符有 3 个:
| 运算符 | 描述 |
| ------ | -------------------------------------------------------- |
| AND | 与,当两个条件都为 真 时,结果为 真 ( Java : && ) |
| OR | 或,当两个条件至少有一个为真时,结果为真 ( Java : \|\| ) |
| NOT | 取反 ( Java: ! ) |
通常,使用逻辑运算符连接多个条件时,一定要考虑条件的优先级和执行顺序。
在复合条件中,优先级高的条件先执行;
如果优先级相同,按照条件出现的先后顺序执行(从左至右);
如果复合条件使用了括号,那么括号内的优先级别高,因此先予执行;
对于逻辑运算符来说,从高到底依次是:`not > and > or`
请务必注意 `or` 的优先级是最低的:
```sql
SELECT id, last_name, salary, dept_id
FROM s_emp
where dept_id = 42 and salary > 1000 or 'abc' = 'abc';
```
这里的 `'abc' = 'abc'` 单纯是为了说明 `or` 的优先级比较低而指定的。
#### 6.1.3、数据分组
##### (1)、组函数
此处仅关注几个常用的组函数:
- `max` 求同一分组中的最大值
- `min` 求同一分组中的最小值
- `avg` 求同一分组中的平均值
- `sum` 对同一组数据求和
- `count` 统计同一分组中的数据个数
- 如果统计的是表中的指定列,当列为空时则会忽略该行数据
应用举例:
- 统计 `emp` 表中所有员工的最低月薪、最高月薪、平均月薪
```sql
SELECT min(sal), max(sal), avg(sal) FROM emp;
```
白话: 如果查询语句中没有 `group by` 子句,则可以认为是将整个表作为一个分组来对待。
- 统计 `emp` 表中有部门号的那些员工的最低月薪、最高月薪、平均月薪
```sql
SELECT min(sal), max(sal), avg(sal)
FROM emp
WHERE deptno IS NOT NULL;
```
白话: 这里要把 `deptno` 不为空的所有员工当作一个分组来对待。
- 统计 `emp` 表中有多少人**提成不为空**
```sql
SELECT count(comm) FROM emp;
```
- 统计 `emp` 表中有多少人的提成大于零
```sql
SELECT count(comm) FROM emp WHERE comm > 0 ;
```
使用组函数时,需注意:
- 组函数**只能**出现在`SELECT`子句、`HAVING`子句、`ORDER BY`子句中
- `SELECT`子句是对查询结果进行“挑选”,此时已经分组,因此可以使用组函数
- `HAVING`子句必须跟在`GROUP BY`之后,此时已经分组,可以用组函数对分组后的数据进行处理
-
- 组函数**不能**出现在 `WHERE` 子句和 `GROUP BY` 子句中
- 不能出现在`WHERE`子句中是因为`WHERE`是对表中数据首次筛选,此时尚未分组
- 不能出现在 `GROUP BY` 子句中是因为分组正在进行中
##### (2)、group by ⼦句
如果需要按照指定条件进行分组,则可以在 查询语句中使用 `group by` 来实现:
```sql
SELECT 列 [, ...]
FROM 表名
[WHERE 过滤条件]
GROUP BY 分组条件 [ , ....]
```
比如,根据 `deptno` 进行对 `emp` 表中的员工进行分组,统计各部门的员工数:
```sql
SELECT deptno, job, count(ename)
FROM emp
GROUP BY deptno, job ;
```
在`SELECT`子句中的列,要么是曾经作为分组条件在`GROUP BY` 子句中出现过的,要么必须经过组函数处理的。
- 前面举例中 `deptno` 就是在 `group by` 子句中出现过的
- 前面举例中的 `ename` 虽然没有在 `group by` 中出现,但是它被 `count` 函数所处理
分组条件中可以使用多个列,只需要在 `group by` 之后依次书写这些列并用逗号隔开即可。
比如,查询 `emp` 表中 每个部门各个岗位 的平均工资:
```sql
SELECT deptno, job, avg(sal)
FROM emp
GROUP BY deptno, job;
```
##### (3)、having ⼦句
在 `GROUP BY` 子句中可以使用 `HAVING` 子句对分组后的数据再次过滤:
```sql
SELECT 列 [, ...]
FROM 表名
[WHERE 过滤条件]
GROUP BY 分组条件 [ , ....]
HAVING 过滤条件 ;
```
比如,查询 `emp` 表中平均工资高于 2000 的部门的部门号和平均工资:
```sql
SELECT deptno, avg(sal)
FROM emp
GROUP BY deptno
HAVING avg(sal) > 2000 ;
```
#### 6.1.4、数据排序
数据排序通过 `ORDER BY` 子句实现,其中 `ASC` 表示 升序,`DESC` 表示降序。
```sql
SELECT 列 [, ...]
FROM 表名
[ WHERE 过滤条件 ]
[ GROUP BY 分组条件 [ HAVING 过滤条件 ] ]
[ ORDER BY 排序条件 ];
```
比如查询 `emp` 表中所有雇员的工号、姓名、入职日期,并根据入职日期升序排列:
```sql
SELECT empno, ename , hiredate FROM emp ORDER BY hiredate ASC;
```
此处的 `ASC` 是可以省略的,因为默认的就是 升序排列。
应用举例:
- 查询`emp`表中所有员工的 工号、姓名、年薪,并根据年薪降序排列
```sql
SELECT empno 工号, ename 姓名, sal * 12 AS 年薪
FROM emp
ORDER BY sal DESC;
```
- 在 `ORDER BY` 之后可以使用 表达式
```sql
SELECT empno 工号, ename 姓名, sal * 12 AS 年薪
FROM emp
ORDER BY sal * 12 DESC;
```
- 在 `ORDER BY` 之后可以使用 列的别名
```sql
SELECT empno 工号, ename 姓名, sal * 12 AS 年薪
FROM emp
ORDER BY 年薪 DESC;
```
- 在 `ORDER BY` 之后可以跟查询结果中各个列的索引
```sql
SELECT empno 工号, ename 姓名, sal * 12 AS 年薪
FROM emp
ORDER BY 3 DESC;
```
- 查询`emp`表中所有员工的工号、姓名、年薪,根据年薪降序、姓名升序排列
```sql
SELECT empno 工号, ename 姓名, sal * 12 AS 年薪, deptno 部门号
FROM emp
ORDER BY 3 DESC, 2 ASC;
```
#### 6.1.5、分页查询
在 `MySQL`中可以通过 `LIMIT` 语句实现分页查询:
```sql
SELECT 列名
FROM 表名
[ WHERE 查询条件 ]
[ GROUP BY 分组条件 [HAVING 筛选条件] ]
[ ORDER BY 排序条件 ]
LIMIT 起始位置, 该页最多行数;
```
应用举例:
- 查询`emp`表所有数据,显示第 `1` 页,每页最多显示 `5` 条数据
```sql
SELECT empno, ename, deptno, job
FROM emp
LIMIT 0, 5 ;
```
- 查询`emp`表所有数据,显示第 `2` 页,每页最多显示 `5` 条数据
```sql
SELECT empno, ename, deptno, job
FROM emp
LIMIT 5, 5 ;
```
- 查询`emp`表所有数据,显示第 `3` 页,每页最多显示 `5` 条数据
```sql
SELECT empno, ename, deptno, job
FROM emp
LIMIT 10, 5 ;
```
- 查询`emp`表所有数据,显示第 `4` 页,每页最多显示 `5` 条数据
```sql
SELECT empno, ename, deptno, job
FROM emp
LIMIT 15, 5 ;
```
### 6.2、高级查询
#### 6.2.1、多表查询
实际应用中,经常会碰到需要查询的数据存在于两个或两个以上的表中的情况,这时就需要使用 select 查询多张表。多表查询比单表查询要复杂许多,本节将详解多表查询技术。
> 国内资料上可能将 多表查询 称作 多表联查。
为了尽可能简单地说明问题,我们创建表结构非常简单的两张表:
- 创建专业表
```sql
CREATE TABLE `t_majors` (
`id` INT auto_increment,
`name` VARCHAR(50),
PRIMARY KEY(`id`)
);
```
- 创建班级表
```sql
CREATE TABLE `t_classes` (
`id` INT auto_increment ,
`name` VARCHAR(50) ,
`major_id` INT(5) ,
FOREIGN KEY( `major_id` ) REFERENCES `t_majors`(`id`),
PRIMARY KEY(`id`)
);
```
创建表之后,分别向专业表(t_majors)和班级表(t_classes)中插入数据:
- 插入专业
```sql
INSERT INTO t_majors ( id , name ) VALUES ( 1 , '软件' );
INSERT INTO t_majors ( id , name ) VALUES ( 2 , '金融' );
```
- 插入班级
```sql
INSERT INTO t_classes ( id , name , major_id ) VALUES ( 1 , '开发' , 1 );
INSERT INTO t_classes ( id , name , major_id ) VALUES ( 2 , '测试' , 1 );
INSERT INTO t_classes ( id , name , major_id ) VALUES ( 3 , '会计' , NULL );
```
专业表中数据结构如下:
| ID | NAME |
| ---- | ---- |
| 1 | 软件 |
| 2 | 金融 |
班级表中数据结构如下:
| ID | NAME | MAJOR_ID |
| ---- | ---- | -------- |
| 1 | 开发 | 1 |
| 2 | 测试 | 1 |
| 3 | 会计 | |
以上准备完毕,即可开始后续学习。
##### (1)、表的别名
表的别名是指在 查询语句 中为表定义的**临时名称**,目的是为了简化对表的引用,方便在其他地方使用。
为表指定别名,只需要在表名称之后使用空格隔开,直接指定别名即可:
```sql
SELECT m.id , m.name FROM t_majors m ;
```
以上查询语句中,为被查询的表 `t_majors` 表取了别名`m`并在`select`子句中予以使用。
表的别名,在使用时以简短为第一原则,兼顾"见名知义",力求简单而又能明显地把不同的表的别名区分开;
```sql
SELECT m.id , m.name , c.id , c.name FROM t_majors m , t_classes c ;
```
这里可以看到,我们可以使用 m.name 、c.name 的方式引用表中的字段,而不需要使用 t_majors.name 和 t_classes.name ,这样的写法在后面即将看到的连接查询非常有用!
表的别名使用规则:
- `where` 子句之后可以跟 表的别名,但不可以跟 列的别名 ;
- `group by` 子句之后可以跟 表的别名 ,但不可以跟 列的别名 ;
- `order by` 子句之后可以跟 表的别名,也可以跟 列的别名,甚至是列的位置 。
##### (2)、笛卡尔乘积
在集合运算中,集合与集合之间的乘积被称为**笛卡尔乘积**。
对于下面查询来说:
```sql
SELECT * FROM t_classes, t_majors ;
```
如果把 `t_classes` 中的记录依次排列到 `x` 轴,把 `t_majors` 表中的记录依次排列到 `y` 轴,在两张表的每条记录点上画出与 `x` 轴、`y` 轴平行的线条,则它们相交的点组成的集合就是**笛卡尔乘积**。
在上面的询语句中,`FROM`关键字之后使用了两张表,类似这种查询两张表或查询两张以上的表的操作,即为**连接查询**(国内资料可能称作**多表查询**或**多表连查**)。
以上查询中,因为没有使用任何条件对数据进行筛选,因此所产生的结果即为笛卡尔乘积,这种查询结果是我们将来需要极力避免的。为了避免这种结果,我们可以在查询语句中使用 *连接条件* 来筛选数据。
所谓**连接条件**,就是用来**避免**产生笛卡尔乘积的条件,它通常是采用两张表中有关联的两个或多个列进行比较。
当查询结果中的所有数据全部都满足连接条件时,这种查询被称作**内连接**(`inner join`)。
当查询结果中除了满足连接条件的数据外,还包含部分不满足条件的数据时,这种查询被称作**外连接**(`outter join`)。
在标准SQL中采用以下形式实现连接查询:
```sql
SELECT 列名
FROM 左表
INNER | [ LEFT OUTER | RIGHT OUTER| FULL OUTER] JOIN 右表
ON 连接条件;
```
注意:
- `JOIN` 可以视为 `FROM` 的子句
- 在 `JOIN` 之前的表就是所谓的 “左表”
- 在 `JOIN` 之后的表就是所谓的 “右表”
- `ON` 可以视为 `JOIN` 的子句
- 在 `ON` 关键字之后就是所谓的 “连接条件”
##### (3)、内连接
查询结果中全部都是满足连接条件的数据行。
###### 等值连接
查询每个员工及其部门,列出工号、姓名、部门号、部门名称。(查询 `emp` 表和`dept`表)
```sql
SELECT e.empno, e.ename, d.deptno, d.dname
FROM emp e
INNER JOIN dept d
ON e.deptno = d.deptno ;
```
其中 `INNER JOIN` 是默认操作,因此可以省略 `INNER` 关键字:
```sql
SELECT e.empno, e.ename, d.deptno, d.dname
FROM emp e
JOIN dept d
ON e.deptno = d.deptno ;
```
此处的连接条件为 `e.deptno = d.deptno` 。
###### 非等值连接
查询`emp`表中各员工的月薪及薪资等级。
```sql
SELECT e.empno, e.ename, e.sal, g.grade
FROM emp e
INNER JOIN salgrade g
ON e.sal >= g.losal AND e.sal < g.hisal ;
```
注意,这里的连接条件是 `e.sal >= g.losal AND e.sal < g.hisal` ,它表示 `e.sal` 在一个区间内,而不是等于具体某个值。
##### (4)、外连接
查询结果中除了完全满足连接条件的数据外,还包含了不满足连接条件的数据行。
###### 左外连接
在查询结果中除了完全满足连接条件的数据外,还包含了**左表**中不满足条件的数据行。
查询各员工及其部门信息,列出工号、姓名、部门号、部门名称,若某个员工没有部门号,也将其包含在查询结果中。
```sql
SELECT e.empno, e.ename, d.deptno, d.dname
FROM emp e
LEFT OUTER JOIN dept d
ON e.deptno = d.deptno ;
```
其中 `OUTER` 关键字可以省略。
###### 右外连接
在查询结果中除了完全满足连接条件的数据外,还包含了**右表**中不满足条件的数据行。
查询各员工及其部门信息,列出工号、姓名、部门号、部门名称,若某个部门没有员工,也将其包含在查询结果中。
```sql
SELECT e.empno, e.ename, d.deptno, d.dname
FROM emp e
RIGHT OUTER JOIN dept d
ON e.deptno = d.deptno ;
```
###### 全外连接
在 标准SQL 中的 全外连接写法为:
```sql
SELECT e.empno, e.ename, d.deptno, d.dname
FROM emp e
FULL OUTER JOIN dept d
ON e.deptno = d.deptno ;
```
MySQL 确实**不直接支持 `FULL OUTER JOIN` 语法**(这是 MySQL 的历史设计限制,直到最新版本仍未原生支持),但可以通过「`LEFT JOIN + RIGHT JOIN + UNION`」的组合方式**模拟全外连接**,效果完全等价于原生全外连接。
```sql
SELECT e.empno, e.ename, d.deptno, d.dname
FROM emp e LEFT OUTER JOIN dept d ON e.deptno = d.deptno
UNION
SELECT e.empno, e.ename, d.deptno, d.dname
FROM emp e RIGHT OUTER JOIN dept d ON e.deptno = d.deptno ;
```
#### 6.2.2、子查询
## 7、事务控制
### 7.1、数据库引擎
MySQL 常用引擎: MyISAM 和 InnoDB 。
其中,InnoDB 是支持事务操作的 引擎,因此建表时建议使用该引擎:
```sql
create table 表名 ( 列名 类型(列宽) 约束 , ... ) engine = InnoDB ;
```
如果建表时没有指定引擎,早期的MySQL默认采用 MyISAM 引擎,该引擎默认不支持事务操作。
故建完表后需要修改引擎:
```sql
alter table 表名 type = InnoDB ;
```
或者使用:
```sql
alter table 表名 engine = InnoDB ;
```
查看修改结果:
```sql
show table status from 数据库名 ;
```
或者使用:
```sql
show create table 表名 ;
```
注意:
我们使用的 MySQL 5.6 及 5.7 、8.x 默认的引擎都是 InnoDB , 因此,建表时无须指定,建表后也无须修改。
### 7.2、事务隔离级别
#### 7.2.1、ANSI/ISO SQL标准定义的 4 种事务隔离级别
| read uncommited | 读未提交 |
| read commited | 读已提交 |
| repeatable read | 可重复读 |
| serializable | 序列化 |
#### 7.2.2、查看当前事务的隔离级别:
```sql
SELECT @@transaction_isolation;
```
#### 7.2.3、设置 InnoDB 的事务级别
第一种方法:
```sql
set 作用域 transaction isolation level 事务隔离级别 ;
```
第一种方法举例:
```sql
set global transaction isolation level read committed; -- global 作用域表示全局的
set session transaction isolation level read uncommitted ; -- session 作用域表示当前会话
set session transaction isolation level read committed;
set session transaction isolation level repeatable read ;
set session transaction isolation level serializable ;
```
第二种方法:
```sql
set 作用域 transaction_isolation = '事务隔离级别' ;
```
第二种方法举例:
```sql
set global transaction_isolation = 'repeatable-read'; -- 全局 ( global )
set session transaction_isolation = 'read-uncommitted'; -- 当前会话 ( session )
set session transaction_isolation = 'read-committed';
set session transaction_isolation = 'serializable';
```
其中的作用域:
- global 表示全局,修改后所有的会话都将生效
- session 表示当前会话,修改后仅针对当前会话有效
修改事务隔离级别后,使用 select @@tx_isolation 来查看修改后的隔离级别。
### 7.3、事务控制语句(TCL)
#### 7.3.1、显式开启一个事务
```sql
begin ;
```
或:
```sql
start transaction ;
```
注意,以上语句在 Oracle 中不适用。
#### 7.3.2、提交事务
```sql
commit ;
```
#### 7.3.3、回滚事务
```sql
rollback ;
```
#### 7.3.4、创建保存点
```sql
savepoint 保存点名称 ;
```
#### 7.3.5、删除某个事务保存点
```sql
release savepoint 保存点名称 ;
```
#### 7.3.6、闪回(回滚)到某个保存点
```sql
rollback to 保存点名称 ;
```
#### 7.3.7、设置事务隔离级别:
参看 7.2.3
#### 7.3.8、禁用 mysql 的自动提交
默认情况下,MySQL默认是自动提交事务的,可以通过以下语句来修改它:
```sql
set autocommit = false ; -- 不要再自动提交
set autocommit = true ; -- 自动提交 (默认值)
```
#### 7.3.9、查看自动提交状态
```sql
mysql> select @@autocommit ;
+--------------+
| @@autocommit |
+--------------+
| 1 |
+--------------+
1 row in set (0.00 sec)
```
其中,1 表示 true (自动提交) ,0 表示false (不自动提交)。
### 7.4、隐式提交事务的SQL
当执行 DDL 语句 或 DCL 时,会导致当前未结束的事务被提交。
(DDL ,数据定义语言,比如 create table 、alter table 、drop table 、truncate table )
(DCL ,数据控制语言,比如 drop user 、grant 等)
## 8、备份与恢复
备份数据通常在命令提示符或终端下,使用 mysqldump 命令完成。
### 8.1、导出整个数据库
```sql
C:\> mysqldump -u 用户名 -p --default-character-set=latin1 数据库名 > 导出的文件名
```
数据库默认的字符编码为 latin1 ,如果创建数据库时指定了编码,请保持一致。
举例:
```sql
C:\> mysqldump -u root -p malajava > C:/malajava.sql
```
### 8.2、导出一张表
```sql
C:\> mysqldump -u 用户名 -p 数据库名 表名 > 导出的文件名
```
举例:
```sql
C:\> mysqldump -u root -p malajava t_students > C:/students.sql
```
### 8.3、导出一个数据库结构
```sql
C:\> mysqldump -u root -p -d –add-drop-table malajava > C:/malajava.sql
```
其中:
- -d 表示仅仅导出表结构,不导出表中的数据
- –add-drop-table 表示在每个 create 语句之前增加一个 drop table 语句
### 8.4、导入数据库
在 mysql 提示符下,使用 source 命令即可导入相应的 sql 脚本:
```sql
mysql> source 数据库脚本 ;
```
举例:
```sql
mysql> source C:/malajava.sql
```
## 9、常用数据类型
《待整理》