MySQL多表&事务

MySQL的多表查询,事务操作,DCL语句

一、多表查询

查询语法

1
2
3
4
5
select
列名列表
from
表名列表
where ...

1.1、案例实现

  1. 数据准备
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 创建部门表
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);

SELECT *FROM emp;
SELECT *FROM dept;
-- 笛卡尔积 A*B
SELECT * FROM emp,dept;
  1. 笛卡尔积:
    • 有两个集合A,B,取这两个集合所有组成情况
    • 要完成多表查询,需要消除无用的数据

1.2、多表查询的分类

1.内连接查询

  1. 隐式内连接:使用where条件消除无用的数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    -- 查询所有员工信息和对应的部门信息
    SELECT * FROM emp,dept WHERE emp.`dept_id`=dept.`id`;
    -- 查询员工表的名称和性别 。部门表的名称
    SELECT NAME emp.`name`,emp.`gender`,dept.`name` FROM emp,dept WHERE emp.`dept_id`=dept.`id`;
    -- 简化 起别名
    SELECT
    t1.`name`,
    t1.gender,
    t2.`name`
    FROM
    emp t1,
    dept t2
    WHERE
    t1.`dept_id`=t2.`id`;
  1. 显示内连接

    • 语法:select 字段列表 from 表名1 inner join 表名2 on 条件

      1
      2
      3
      SELECT * FROM emp INNER JOIN dept ON emp.`dept_id`=dept.`id`;	
      -- inner 可以省略
      SELECT * FROM emp JOIN dept ON emp.`dept_id`=dept.`id`;
    1. 内连接查询

      1. 从哪些表查询查询数据
      2. 条件是什么
      3. 查询哪些字段

2. 外连接查询

  1. 左外连接:

    • 语法:select 字段列表 from 左表 left outer join 右表 on 条件; outer可以省略

    • 查询的是左表所有数据及其交集部分

      1
      SELECT t1.*,t2.`name`FROM emp t1 LEFT JOIN dept t2 ON t1.`dept_id`=t2.`id`;
  2. 右外连接:

    • 语法:select 字段列表 from 左表 right outer join 右表 on 条件; outer可以省略
    • 查询的是右表所有数据及其交集部分

3.子查询

  1. 概念:查询中嵌套查询,称嵌套查询为子查询。

    1
    2
    3
    4
    5
    6
    7
    8
    -- 查询工资最高的员工信息
    -- 1.查询最高的工资是多少
    SELECT MAX(salary) FROM emp;
    -- 查询员工信息,并且工资等于9000的
    SELECT * FROM emp WHERE emp.`salary`=9000;

    -- 一条sql就完成这个操作 子查询
    SELECT * FROM emp WHERE emp.`salary`=(SELECT MAX(salary) FROM emp);
    1. 子查询不同情况

      扫描二维码关注公众号,回复: 11452861 查看本文章
      1. 子查询的结果是单行单列的:
      • 子查询可以作为条件,使用运算符去判断。运算符: > < >= <= == <>

        1
        2
        -- 查询员工工资小于平均工资的人
        SELECT * FROM emp WHERE emp.`salary`<(SELECT AVG(emp.`salary` ) FROM emp);
2. 子查询的结果是多行单列的:

* 子查询可以作为条件,使用运算符 in 来判断
    
    
1
2
3
4
5
6
-- 查询'财务部'和'市场部"所有的员工信息
SELECT id FROM dept WHERE NAME = '财务部' OR NAME = '市场部';
SELECT * FROM emp WHERE emp.`dept_id`=3 OR emp.`dept_id`=2 ;
SELECT * FROM emp WHERE dept_id IN (3,2);
-- 子查询
SELECT * FROM emp WHERE dept_id IN (SELECT id FROM dept WHERE NAME = '财务部' OR NAME = '市场部');
3. 子查询的结果是多行多列的: * 子查询可以作为一张虚拟表参与查询
1
2
3
4
5
6
7
-- 查询员工入职日期是2011-11-11日之后的员工信息和部门信息
-- 子查询
SELECT * FROM emp WHERE emp.`join_date`>'2011-11-11';
SELECT * FROM dept t1,(SELECT * FROM emp WHERE emp.`join_date`>'2011-11-11') t2 WHERE t2.dept_id = t1.`id`;

-- 普通内连接
SELECT * FROM emp t1,dept t2 WHERE t1.`dept_id`=t2.`id` AND t1.`join_date`>'2011-11-11';
### 4.多表查询练习
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
-- 部门表
CREATE TABLE dept (
id INT PRIMARY KEY PRIMARY KEY, -- 部门id
dname VARCHAR(50), -- 部门名称
loc VARCHAR(50) -- 部门所在地
);

-- 添加4个部门
INSERT INTO dept(id,dname,loc) VALUES
(10,'教研部','北京'),
(20,'学工部','上海'),
(30,'销售部','广州'),
(40,'财务部','深圳');



-- 职务表,职务名称,职务描述
CREATE TABLE job (
id INT PRIMARY KEY,
jname VARCHAR(20),
description VARCHAR(50)
);

-- 添加4个职务
INSERT INTO job (id, jname, description) VALUES
(1, '董事长', '管理整个公司,接单'),
(2, '经理', '管理部门员工'),
(3, '销售员', '向客人推销产品'),
(4, '文员', '使用办公软件');



-- 员工表
CREATE TABLE emp (
id INT PRIMARY KEY, -- 员工id
ename VARCHAR(50), -- 员工姓名
job_id INT, -- 职务id
mgr INT , -- 上级领导
joindate DATE, -- 入职日期
salary DECIMAL(7,2), -- 工资
bonus DECIMAL(7,2), -- 奖金
dept_id INT, -- 所在部门编号
CONSTRAINT emp_jobid_ref_job_id_fk FOREIGN KEY (job_id) REFERENCES job (id),
CONSTRAINT emp_deptid_ref_dept_id_fk FOREIGN KEY (dept_id) REFERENCES dept (id)
);

-- 添加员工
INSERT INTO emp(id,ename,job_id,mgr,joindate,salary,bonus,dept_id) VALUES
(1001,'孙悟空',4,1004,'2000-12-17','8000.00',NULL,20),
(1002,'卢俊义',3,1006,'2001-02-20','16000.00','3000.00',30),
(1003,'林冲',3,1006,'2001-02-22','12500.00','5000.00',30),
(1004,'唐僧',2,1009,'2001-04-02','29750.00',NULL,20),
(1005,'李逵',4,1006,'2001-09-28','12500.00','14000.00',30),
(1006,'宋江',2,1009,'2001-05-01','28500.00',NULL,30),
(1007,'刘备',2,1009,'2001-09-01','24500.00',NULL,10),
(1008,'猪八戒',4,1004,'2007-04-19','30000.00',NULL,20),
(1009,'罗贯中',1,NULL,'2001-11-17','50000.00',NULL,10),
(1010,'吴用',3,1006,'2001-09-08','15000.00','0.00',30),
(1011,'沙僧',4,1004,'2007-05-23','11000.00',NULL,20),
(1012,'李逵',4,1006,'2001-12-03','9500.00',NULL,30),
(1013,'小白龙',4,1004,'2001-12-03','30000.00',NULL,20),
(1014,'关羽',4,1007,'2002-01-23','13000.00',NULL,10);



-- 工资等级表
CREATE TABLE salarygrade (
grade INT PRIMARY KEY, -- 级别
losalary INT, -- 最低工资
hisalary INT -- 最高工资
);

-- 添加5个工资等级
INSERT INTO salarygrade(grade,losalary,hisalary) VALUES
(1,7000,12000),
(2,12010,14000),
(3,14010,20000),
(4,20010,30000),
(5,30010,99990);

-- 需求:

-- 1.查询所有员工信息。查询员工编号,员工姓名,工资,职务名称,职务描述
/*
分析:
1.员工编号,员工姓名,工资,需要查询emp表 职务名称,职务 需要查询job表
2.查询条件 emp.job_id = job.id
*/
SELECT
t1.`id`, -- 员工编号
t1.`ename`, -- 员工姓名
t1.`salary`,-- 工资
t2.`jname`, -- 职务名称
t2.`description`--职务
FROM
emp t1,
job t2
WHERE
t1.`job_id`=t2.id;

-- 2.查询员工编号,员工姓名,工资,职务名称,职务描述,部门名称,部门位置
/*
分析:
1.员工编号,员工姓名,工资,需要查询emp表 职务名称,职务描述需要查询job表 部门名称,部门位置 需要查询dept表
2.查询条件 emp.job_id = job.id AND emp.dept_id =dept.id
*/
SELECT
t1.`id`, -- 员工编号
t1.`ename`,-- 员工姓名
t1.`salary`, -- 工资
t2.`jname`, -- 职务名称
t2.`description`, -- 职务描述
t3.`dname`, -- 部门名称
t3.`loc` -- 部门位置
FROM
emp t1,job t2,dept t3
WHERE
t1.`job_id`=t2.`id` AND t1.`dept_id`=t3.`id`;
-- 3.查询员工姓名,工资,工资等级
/*
分析:
1.员工姓名,工资 emp表 工资等级 salarygrade表
2.emp.salary>=salarygrade.losalary and emp.salary<=salarygrade.hisalary
或者 between ... and ...
*/
SELECT
t1.`ename`, -- 员工姓名
t1.`salary`,-- 工资
t2.`grade` -- 工资等级
FROM
emp t1 , salarygrade t2
WHERE
t1.salary>=t2.losalary AND t1.salary<=t2.hisalary;

-- 4.查询员工姓名,工资,职务名称,职务描述,部门名称,部门位置,工资等级
/*
1.员工姓名,工资,emp 职务名称,职务描述job 部门名称,部门位置,dept 工资等级 salarygrade
2.emp.job_id = job.id AND emp.dept_id =dept.id mp.job_id = job.id AND emp.dept_id =dept.id emp.salary>=salarygrade.losalary and emp.salary<=salarygrade.hisalary
*/
SELECT
t1.`ename`,
t1.`salary`,
t2.`jname`,
t2.`description`,
t3.`dname`,
t3.`loc`,
t4.`grade`

FROM
emp t1, job t2,dept t3,salarygrade t4
WHERE
t1.`job_id`=t2.`id` AND t1.`dept_id`=t3.id AND t1.`salary`<=t4.`hisalary` AND t1.`salary`>=t4.`losalary`;
-- 5.查询出部门编号、部门名称、部门位置、部门人数
/*
分析:
1.部门编号 emp 部门名称、部门位置 dept 部门人数 count
2.使用分组查询。安装emp.dept_id完成分组,查询count(id)
3.使用子查询将第2步的查询结果和dept表进行关联查询
SELECT 字段 1,字段 2... FROM 表名 GROUP BY 分组字段 [HAVING 条件];
*/

SELECT
t1.`id`,t1.`dname`,t1.`loc`,t2.total
FROM
dept t1,
(SELECT
dept_id,
COUNT(id) total
FROM
emp
GROUP BY
dept_id) t2

WHERE
t1.`id`=t2.dept_id;
-- 6.查询所有员工的姓名及其直接上级的姓名,没有领导的员工也需要查询
-- 6.查询所有员工的姓名及其直接上级的姓名,没有领导的员工也需要查询
/*
分析:
1.姓名 emp 直接上级的姓名 emp
* emp表的id 和 mgr是自关联
2.条件 emp.id = emp.mgr
3.查询左表的所有数据,和 交集数据
SELECT t1.*,t2.`name`FROM emp t1 LEFT JOIN dept t2 ON t1.`dept_id`=t2.`id`;
SELECT
t1.`ename`,
t1.mgr,
t2.id,
t2.`ename`
FROM
emp t1 ,emp t2
WHERE
t1.`mgr`=t2.`id`;

*/

SELECT
t1.`ename`,
t1.`mgr`,
t2.`id`,
t2.`ename`
FROM emp t1
LEFT JOIN emp t2
ON t1.`mgr`=t2.`id`;

二、 事务

1. 事物的基本介绍

  1. 概念:如果一个包含多个步骤的业务操作,被事务管理,这些操作要么同时成功,要么同时失败。

  2. 操作:

    1. 开启事务: start transaction

    2. 回滚:rollback,将事务还原到事务开启时的状态

    3. 提交:commit,提交操作

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      create table account(
      id INT PRIMARY KEY AUTO_INCREMENT,
      name VARCHAR(20),
      balance DOUBLE
      );
      -- 添加数据
      INSERT INTO account (name,balance) VALUES ('zhangsan'),('lisi')
      -- 开启事务
      START TRANSACTION;
      -- zhangsan给lisi转账500元`UPDATE 表名 SET 字段名=值 WHERE 字段名=值;`
      -- 张三账户 -500
      UPDATE account SET balance = balance -500 WHERE NAME = 'zhangsan';
      -- 出错了
      -- lisi账户 +500
      UPDATE account SET balance = balance +500 WHERE NAME = 'lisi';
      -- 发现出问题了,回滚事务
      ROLLBACK;
      -- 发现执行没有问题 提交事务
      COMMIT;
      4. MySQL数据库中事务默认自动提交
      • 一条DML(增删改)语句会自动提交一次事务。

      • 事务提交的两种方式:

        • 自动提交:MySQL就是自动提交的,一条DML(增删改)语句会自动提交一次事务。
        • 手动提交:oracle数据库默认手动提交,需要先开启事务,再使用commit提交
      • 修改事务的默认提交方式:

        • 查看事务的默认提交方式:SELECT @@autocommit;

          ​ 结果为 1 代表自动提交

          ​ 结果为 0 代表手动提交

        • 修改默认提交方式:set @@autocommit =0

2. 事物的四大特征

1. 原子性:是不可分割的最小操作单位,要么同时成功,要么同时失败

2. 持久性:当事务提交或回滚后,数据库会持久化的保存数据。

3. 隔离性:多个事务之间。相互独立。

4.一致性:事务操作前后,数据总量不变。

3. 事物的隔离级别

1. 概念:多个事务之间是隔离的,相互独立的。但是如果多个事务操作同一批数据,则会引发一些问题,设置不同的隔离级别就可以解决这些问题。
 2. 存在的问题:
      1. 脏读:一个事务,读取到另一个事务中没有提交的数据。
      2. 不可重复读(虚读):再同一个事务中,两次读取到的数据不一样。
      3. 幻读:一个事务操作(DML)数据表中所有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改。
  1. 隔离级别:

    1. read uncommitted:读未提交
      • 产生的问题:脏读、不可重复读、幻读
    2. read committed:读已提交 (Oracle默认)
      • 产生的问题:不可重复读,幻读
    3. repeatable read:不可重复读 (MySQL默认)
      • 产生的问题:幻读
    4. serializable:串行化
      • 可以解决所有的问题

    注意:隔离级别从小到大安全性越来越高,但是效率越来越低

    • 数据库隔离级别:

      查询隔离级别 : select @@tx_isolation;

      设置隔离级别 :set global transaction isolation level 级别字符串;

  2. 演示

    1
    2
    3
    4
    5
    SET GLOBAL TRANSACTION ISOLATION LEVEL  read uncommitted; -- 设置隔离级别
    start transaction; -- 开启事务
    -- 转账操作
    update account set balance = balance - 500 where id =1;
    update account set balance = balance + 500 where id =2;

三、DCL

SQL分类

  1. DDL:操作数据库和表
  2. DML:操作增删改表征数据
  3. DQL:查询表中数据
  4. DCL:管理用户,授权

DBA:数据库管理员

1. 管理用户

  1. 添加用户

    • 语法:CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码’;

      1
      2
      3
      4
      -- 创建用户
      CREATE USER 'yangye'@'localhost' IDENTIFIED BY '123';
      -- 创建用户 任意主机都可以登录
      CREATE USER 'yangye'@'%' IDENTIFIED BY '123';
  1. 删除用户

    • 语法:DROP USER '用户名'@'主机名';
  2. 修改用户密码

    • 语法:

      UPDATE USER SET PASSWORD = PASSWORD('新密码') WHERE USER = '用户名';

      SET PASSWORD FOR '用户名'@'主机名' = PASSWORD('新密码');

      1
      2
      SET PASSWORD FOR 'yang'@'%' = PASSWORD('abc');
      UPDATE USER SET PASSWORD = PASSWORD('abc') WHERE USER = 'yang';
    • MySQL中忘记root用户密码?

      1. cmd –> net stop mysql停止mysql服务

        注意:需要使用管理员权限运行cmd

      2. 使用无验证方式启动mysql服务:

        1
        mysqld --skip-grant-tables
      3. 打开新的cmd窗口,直接输入mysql命令,敲回车。就可以登陆成功

      4. use mysql

      5. update user set password = password('你的新密码') where user ='root';

      6. 关闭两个窗口

      7. 打开任务管理器,手动结束mysqld.exe的进程

      8. 启动mysql服务

      9. 使用新密码登录

  3. 查询用户:

    1. 切换到MySQL数据库:USE mysql;

    2. 查询user表:SELECT * FROM USER;

      通配符:% 表示可以再任意主机使用用户登录数据库

2. 权限管理

  1. 查询权限:SHOW GRANTS FOR '用户名'@'主机名';

    1
    SHOW GRANTS FOR 'yang'@'%';
  2. 授予权限:GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机名';

    1
    2
    3
    4
    5
    6
    -- 单个权限授予
    GRANT SELECT ON db3.account TO 'yang'@'%';
    -- 多个权限授予
    GRANT SELECT,DELETE,UPDATE ON db3.account TO 'yang'@'%';
    -- 授予所有权限,在任意数据库任意表
    GRANT ALL ON *.* TO '用户名'@'主机名';

    注意:通配符 * .* 所有数据库索引表 ALL 所有权限

  3. 撤销权限

    • 语法:revoke 权限列表 on 数据库名.表名 from '用户名'@'主机名';

[TOC]

猜你喜欢

转载自blog.csdn.net/qq_45370568/article/details/106817818