初识MySQL(三) 多表查询,事务,DCL
一. 多表查询
1. 数据准备:
# 创建部门表
CREATE TABLE dept(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
)
INSERT INTO dept (NAME) VALUES ('开发部'),('市场部'),('财务部');
# 创建员工表
CREATE TABLE emp (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
gender CHAR(1), -- 性别
salary DOUBLE, -- 工资
join_date DATE, -- 入职日期
dept_id INT,
FOREIGN KEY (dept_id) REFERENCES dept(id) -- 外键,关联部门表(部门表的主键)
)
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('孙悟空','男',7200,'2013-02-24',1);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('猪八戒','男',3600,'2010-12-02',2);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('唐僧','男',9000,'2008-08-08',2);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('白骨精','女',5000,'2015-10-07',3);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('蜘蛛精','女',4500,'2011-03-14',1);
2. 多表查询的作用:
比如:我们想查询孙悟空的名字和他所在的部门的名字,则需要使用多表查询。
如果一条 SQL 语句查询多张表,因为查询结果在多张不同的表中。每张表取 1 列或多列。
- 多表查询的分类:
3. 笛卡尔积现象:
– 需求:查询所有的员工和所有的部门
select * from emp,dept;
查询结果为:
结果分析:
左边的每条数据和右边的每条数据组合,这种效果被称为笛卡尔积。
所以要完成多表查询,我们需要消除笛卡尔积的影响。
– 设置过滤条件:
select * from emp,dept where emp.`dept_id` = dept.`id`;
– 查询员工和部门的名字
SELECT emp.`name`, dept.`name` FROM emp,dept WHERE emp.`dept_id` = dept.`id`;
4. 内连接查询
用左边表的记录去匹配右边表的记录,如果符合条件的则显示。如:从表.外键=主表.主键;
4.1 隐式内连接:
语法:
SELECT 字段名 FROM 左表, 右表 WHERE 条件
- 示例:
select * from emp,dept where emp.dept_id = dept.id;
4.2 显示内连接
使用 INNER JOIN … ON 语句, 可以省略 INNER;
- 语法:
SELECT 字段名 FROM 左表 [INNER] JOIN 右表 ON 条件;
演示:
SELECT * FROM emp e JOIN dept d ON e.`dept_id`=d.`id`;
5. 外连接查询
5.1 左外连接:
使用 LEFT OUTER JOIN … ON, OUTER 可以省略
- 语法:
SELECT 字段名 FROM 左表 LEFT [OUTER] JOIN 右表 ON 条件
- 查询的是左表所有数据以及其交集部分。
- 演示:
-- 使用左外连接查询
SELECT * FROM dept d LEFT JOIN emp e ON d.`id` = e.`dept_id`;
注意:
-- 在部门表中增加一个销售部
INSERT INTO dept (NAME) VALUES ('销售部');
SELECT * FROM dept;
-- 使用左外连接查询
SELECT * FROM dept d LEFT JOIN emp e ON d.`id` = e.`dept_id`;
5.2 右外连接:
使用 RIGHT OUTER JOIN … ON, OUTER 可以省略
- 语法:
SELECT 字段名 FROM 左表 RIGHT [OUTER ]JOIN 右表 ON 条件
- 查询的是右表所有数据以及其交集部分。
- 演示:
-- 使用右外连接查询
SELECT * FROM dept d RIGHT JOIN emp e ON d.`id` = e.`dept_id`;
6. 子查询
6.1 子查询的概念:
- 一个查询的结果做为另一个查询的条件
- 有查询的嵌套,内部的查询称为子查询
- 子查询要使用括号
6.2 子查询结果的三种情况
- 子查询的结果是单行单列
语法:
SELECT 查询字段 FROM 表 WHERE 字段=(子查询) ;
子查询可以作为条件,使用运算符去判断。 运算符: > >= < <= =等。
演示:
– 1 查询工资低于平均工资的员工信息
SELECT * FROM emp WHERE salary < (SELECT AVG(salary) FROM emp);
- 子查询的结果是多行单列
子查询结果是单例多行,结果集类似于一个数组,父查询使用 IN 运算符
语法:
SELECT 查询字段 FROM 表 WHERE 字段 IN (子查询) ;
演示:
– 查询工资大于 5000 的员工,来自于哪些部门的名字
SELECT NAME FROM dept WHERE id IN (SELECT dept_id FROM emp WHERE salary>5000);
- 子查询的结果是多行多列
语法:
SELECT 查询字段 FROM (子查询) 表别名 WHERE 条件;
注意:子查询作为表需要取别名,否则这张表没有名称则无法访问表中的字段
演示:
– 查询出 2011 年以后入职的员工信息,包括部门名称
SELECT * FROM dept d, (SELECT * FROM emp WHERE join_date >='2011-1-1') e WHERE d.`id`= e.dept_id ;
二. 事务
1. 什么是事务
在实际的开发过程中,一个业务操作如:转账,往往是要多次访问数据库才能完成的。转账是一个用户扣钱,另一个用户加钱。如果其中有一条 SQL 语句出现异常,这条 SQL 就可能执行失败。
事务执行是一个整体, 所有的 SQL 语句都必须执行成功。如果其中有 1 条 SQL 语句出现异常, 则所有的SQL 语句都要回滚,整个业务执行失败。
2. 事务的操作:
- 开启事务: start transaction;
- 回滚:rollback;
- 提交:commit;
- 演示:
CREATE TABLE account (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
balance DOUBLE
);
-- 添加数据
INSERT INTO account (NAME, balance) VALUES ('zhangsan', 1000), ('lisi', 1000);
SELECT * FROM account;
UPDATE account SET balance = 1000;
-- 张三给李四转账 500 元
-- 0. 开启事务
START TRANSACTION;
-- 1. 张三账户 -500
UPDATE account SET balance = balance - 500 WHERE NAME = 'zhangsan';
-- 2. 李四账户 +500
-- 出错了...
UPDATE account SET balance = balance + 500 WHERE NAME = 'lisi';
-- 发现执行没有问题,提交事务
COMMIT;
-- 发现出问题了,回滚事务
ROLLBACK;
SELECT * FROM account;
3. 事务提交的两种方式
- 自动提交:
* mysql就是自动提交的
* 一条DML(增删改)语句会自动提交一次事务。 - 手动提交:
* Oracle 数据库默认是手动提交事务
* 需要先开启事务,再提交 - 修改事务的默认提交方式:
* 查看事务的默认提交方式:SELECT @@autocommit;
-1: 代表自动提交
0 : 代表手动提交
* 修改默认提交方式: set @@autocommit = 0;
4. 事务的四大特征:
- 原子性:是不可分割的最小操作单位,要么同时成功,要么同时失败。
- 持久性:当事务提交或回滚后,数据库会持久化的保存数据。
- 隔离性:多个事务之间。相互独立。
- 一致性:事务操作前后,数据总量不变
5. 事务的隔离级别(了解)
5.1 概念
多个事务之间隔离的,相互独立的。但是如果多个事务操作同一批数据,则会引发一些问题,设置不同的隔离级别就可以解决这些问题。
5.2 存在问题:
- 脏读:一个事务,读取到另一个事务中没有提交的数据
- 不可重复读(虚读):在同一个事务中,两次读取到的数据不一样。
- 幻读:一个事务操作(DML)数据表中所有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改。
5.3 隔离级别:
-
read uncommitted:读未提交
产生的问题:脏读、不可重复读、幻读 -
read committed:读已提交 (Oracle)
产生的问题:不可重复读、幻读 -
repeatable read:可重复读 (MySQL默认)
产生的问题:幻读 -
serializable:串行化
可以解决所有的问题 -
注意:隔离级别从小到大安全性越来越高,但是效率越来越低
-
数据库查询隔离级别:
- select @@tx_isolation;
-
数据库设置隔离级别:
- set global transaction isolation level 级别字符串;
三. DCL
- DCL : 管理用户,授权;
我们现在默认使用的都是 root 用户, 超级管理员, 拥有全部的权限。但是, 一个公司里面的数据库服务器上面
可能同时运行着很多个项目的数据库。所以, 我们应该可以根据不同的项目建立不同的用户, 分配不同的权限来管
理和维护数据库。
注: mysqld 是 MySQL 的主程序,服务器端。 mysql 是 MySQL 的命令行工具,客户端。
1. 管理用户
- 添加用户:
语法:
CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
- 删除用户:
语法:
DROP USER '用户名'@'主机名';
- 修改用户密码:
语法:
UPDATE USER SET PASSWORD = PASSWORD('新密码') WHERE USER = '用户名';
当然,也可以简化一点:
SET PASSWORD FOR '用户名'@'主机名' = PASSWORD('新密码');
-
mysql中忘记了root用户的密码?
- cmd – > net stop mysql 停止mysql服务
* 需要管理员运行该cmd - 使用无验证方式启动mysql服务: mysqld --skip-grant-tables
- 打开新的cmd窗口,直接输入mysql命令,敲回车。就可以登录成功
- use mysql;
- update user set password = password(‘你的新密码’) where user = ‘root’;
- 关闭两个窗口
- 打开任务管理器,手动结束mysqld.exe 的进程
- 启动mysql服务
- 使用新密码登录。
- cmd – > net stop mysql 停止mysql服务
-
查询用户:
- 切换到mysql数据库
USE myql; - 查询user表
SELECT * FROM USER;
- 通配符: % 表示可以在任意主机使用用户登录数据库
2. 权限管理:
- 查询权限:
语法
SHOW GRANTS FOR '用户名'@'主机名';
- 授予权限:
语法:
grant 权限列表 on 数据库名.表名 to '用户名'@'主机名';
- 撤销权限:
语法:
revoke 权限列表 on 数据库名.表名 from '用户名'@'主机名';