MySQL基础(五)事务、DCL权限控制、视图、同义词、索引及练习
目录
九、事务(重要)
9.1 转账操作
9.2 事务操作
9.3 事务的基本实现原理
9.4 事务的特性
9.5 事务并发问题
9.6 事务的隔离级别
十、权限控制DCL操作(了解)
10.1 用户的操作
10.2 授权
10.3 撤销授权
十一、视图(了解)
11.1 视图介绍
11.2 视图语法
11.3 视图构建
11.4 视图使用
11.5 删除视图
十二、同义词(了解)
十三、索引
十四、综合练习
14.1 外键约束的补充(了解)
14.2 查询操作练习
14.2.1 查询每个部门最高薪水的人员名称
14.2.2 查询哪些员工薪资在部门的平均薪资之上
14.2.3 查询每个部门的平均薪资等级
14.2.4 查询平均薪资最高的部门名称
14.2.5 查询薪水比自己领导还高的员工信息。
14.2.6 查询比普通员工的最高薪资还要高的领导名称
14.2.7 查询每个薪资等级有多少个员工
14.2.8 查询出入职时间早于其领导的员工信息和部门信息
14.2.9 查询出至少有5位员工的部门信息
14.2.10 查询出薪资高于公司薪资的平均水平的员工名称,所在部门,上级领导名称,员工名称的薪资等级
14.2.11 查询与'SCOTT'从事相同工作的员工名称和部门名称
14.2.12 查询没有员工的部门信息(exists)
14.2.13 查询部门的平均薪资,以2000作为点,返回'大于2000'或者'小于2000'或者'等于2000'的结果
14.3 常见错误
九、事务(重要)
9.1 转账操作
生活当众,转账是从一方扣钱,另一方加钱,采用数据库来模拟一下这个操作。
优先准备好转账的环境。
# 创建一个账户表 create table account( id bigint primary key auto_increment comment '账户标识', name varchar(16) not null comment '账户名称', money bigint not null comment '账户余额' )comment '账户表'; # 添加两个账户信息,张三、李四,一人1000大洋 insert into account (name,money) values ('张三',1000),('李四',1000); # 模拟张三给李四转500大洋 update account set money = money - 500 where id = 1; update account set money = money + 500 where id = 2;转账分为两个操作,需要先给一个用户扣钱,再给一个用户加钱。
第一个扣钱的操作成功了,但是因为一些其他的原因,比如服务器断点,或者是一些异常情况,导致第二个加钱的SQL执行失败。整个转账的业务其实是失败的,但是第一个的钱扣了,没了。。。。。
正常应当是,这 两个操作要么都执行成功,要么都执行失败。
上述的转账问题,咱们就可以基于事务来解决。
事务可以看做是一个最小的执行单位,一个事务可以由一条或者多条SQL语句组成。 一个事务操作,所有的SQL语句要么都执行成功,要么都执行失败。
9.2 事务操作
首先MySQL他模式就是开启事务的,但是这个事务每执行一个DML语句,都会自动的提交结束。
通过几个操作来实现自己对事务的控制。
开启事务:
1、因为MySQL默认自动结束事务的,咱们可以自己关闭这种自动结束的操作。
2、也可以通过单独的指令,来指定事务开始和结束的位置。
set AutoCommit = 0; -- 默认情况,值是1,代表每次自动结束事务,设置为0,代表需要咱们手动的结束事务。 begin; -- 开启手动结束事务操作,需要在执行完SQL语句后,自己去执行结束事务的指令 start transaction; -- 跟begin是一样的。。。。结束事务:
1、如果开启事务的所有SQL语句,执行没有问题,可以直接提交事务。
2、如果开启事务后执行的SQL语句存在问题,可以执行回滚事务操作。
commit; -- 提交事务,事务中的操作都会落到磁盘当众 rollback; -- 回滚事务,事务中的操作全部都会恢复到事务开启之前的状态。将前面的转账操作,基于事务控制,解决前面的问题。
# 模拟张三给李四转500大洋 set AutoCommit = 1; -- 关闭自动结束事务,需要遇到commit或者rollback才会结束这个事务 begin; -- 手动开启了一个事务,需要遇到commit或者rollback才会结束这个事务。 start transaction; -- 也是手动开启一个事务。 update account set money = money - 500 where id = 1; update account set money = money + 500 where id = 2; commit; rollback; -- 事务结束有两种方式。commit,提交。 rollback,回滚。
9.3 事务的基本实现原理
9.4 事务的特性
原子性(Atomicity) 事务是一个最小的执行单位,一次事务的操作要么都成功,要么都失败。
一致性(Consistency) 表示一个事务内有一个操作失败时,所有的更改过的数据都必须回滚到修改前的状态。
隔离性(Isolation) 事务查看数据操作时数据所处的状态,要么是另一个并发事务修改之前的状态,要么是另一个事务修改它之后的状态,事务不会查看中间状态的数据。
持久性(Durablility) 事务正常提交后,会将数据落到磁盘中,影响是永久了。
9.5 事务并发问题
脏读:一个事务中,读取到了另一个事务未提交的数据。(这个问题必须要解决)
不可重复读:一个事务中,多次查询同一个数据,结果不一致。原因是其他事务中对这个数据修改了,并且提交事务了。
幻读:一个事务中,多次查询同一个数据,结果不一致。原因是其他事务中对某个数据进行了增删,并且提交事务了。
为了复现上述的问题,优先将MySQL的事务隔离级别调低
-- 为了查看到所有问题的效果,这里优先将事务的隔离级别设置为最低等级。READ-UNCOMMITTED。 set global transaction_isolation = 'READ-UNCOMMITTED'; -- 因为设置的是全局的事务隔离级别,设置完毕后,关闭连接,重新打开,才会生效。 select @@transaction_isolation;
复现脏读效果:
复现不可重复读效果:
复现幻读的效果:
9.6 事务的隔离级别
事务的隔离级别就是用来解决前面9.5聊到的事务并发的三个问题的。
READ-UNCOMMITTED(读未提交):可以读取到未提交事务的数据。
(一个问题都不能解决)
READ-COMMITTED(读已提交):可以读取到已经提交事务的数据。
(只能解决脏读)
Oracle默认隔离级别是READ-COMMITTED
REPEATABLE-READ(可重复读):会让一次事务多次查询同一数据结果一致(修改导致)。
(可以解决脏读和不可重读)
MySQL默认隔离级别是可重复读REPEATABLE-READ
SERIALIZABLE(串行化):上锁,所有问题都能解决。
(可以解决所有问题)
为了解决上面说道的各种问题,这里可以设置事务的隔离级别,然后查看效果
查看事务的隔离级别的方式:
select @@transaction_isolation;设置事务的隔离级别,可以设置全局的,也可以针对当前连接设置。
-- 全局的事务隔离级别设置。(设置完,需要关闭连接,重新打开) set global transaction_isolation = 'SERIALIZABLE'; -- 当前会话的事务隔离级别设置。 set session transaction_isolation = 'SERIALIZABLE';
十、权限控制DCL操作(了解)
DCL就是Data Control Language,一般就是对于用户的权限做一些授权操作之类的内容。 直接构建用户,基于用户操作对应库表的权限。
10.1 用户的操作
创建用户: create user 用户名@IP地址 identified by 密码;
这里的IP地址,是指定Host列,也就是当前用户可以基于哪个IP地址连接当前MySQL
创建一个用户,用户名是zheng,密码是zheng,采用默认的IP,%。
#创建一个用户,用户名是zheng,密码是zheng。 create user 'zheng' identified by 'zheng'; create user 'zhang'@'%' identified by 'zhang';
删除用户:drop user 用户名;
删除上面的用户zhang。
# 删除上面的用户zhang。 drop user 'zhang';
Ps:创建完毕的用户,密码插件默认是caching_sha2_password,正常黑窗口是可以连接的。我提供的Navicat版本比较低,所以无法连接,需要将密码插件修改为mysql_native_password。
10.2 授权
给用户赋予操作指定库和表的权限。
语法:grant all on 库名.表名 to 用户名;
all代表赋予这个库和表的所有操作权限。
库名和表名如果想赋予全部的,使用*代替。
赋予zheng用户,可以操作test库下所有表的所有操作权限。
# 赋予zheng用户,可以操作test库下所有表的所有操作权限。 grant all on test.* to 'zheng';发现赋予权限后,依然无法连接,原因是zheng用户默认的密码插件是caching_sha2_password。咱们的Navicat版本低,无法识别,通过alter语句修改一下插件信息
alter user 'zheng'@'%' identified with mysql_native_password by 'zheng';正常连接后,可以看到具体的赋予权限的库表信息。
10.3 撤销授权
将前面赋予的权限撤销掉。
语法:revoke all on 库名.表名 from 用户名;
撤销掉对zheng用户赋予的test库中所有表的所有权限
# 撤销掉对zheng用户赋予的test库中所有表的所有权限 revoke all on test.* from 'zheng';
十一、视图(了解)
11.1 视图介绍
视图(View),是一张虚拟表,在本地磁盘是没有存储的。
视图是从一张表或者多张表中查询出来的结果,作用和真实的表是一样的,包含一系列带有行和列的数据。
在视图中,用户可以通过select语句查询视图里的数据,也可以基于insert,update,delete按修改视图的数据,但是修改视图的本质就是在修改原始表。一般不允许做修改视图的操作。
视图的核心作用是可以将一些非常复杂的查询逻辑封装到一个视图里,同时也可以将一些敏感数据规避。
视图的本质,就是一个SQL。
11.2 视图语法
构建视图语法:create view 视图名 as (查询语句);
视图的构建很简单,只要有对应的查询语句即可。
但是记住,视图无法提升你的查询效率,视图的本质就是一个查询语句。
视图的出现是为了刚方便咱们的操作。。
11.3 视图构建
将之前玩的employee表中薪资大于5000的信息数据封装为一个视图
薪资大于5000,就是where salary > 5000。
查询SQL搞定,直接封装视图即可。
# 将之前玩的employee表中薪资大于5000的信息数据封装为一个视图 select * from t_employees where salary > 5000; # 构建为视图 create view v_emp_salary_gt_fivethousand as (select * from t_employees where salary > 5000);
11.4 视图使用
视图的使用和正常操作表是一样的。
前面构建好的v_emp_salary_gt_fivethousand就可以直接查询
# 查询视图 select first_name,last_name from v_emp_salary_gt_fivethousand;视图是可以修改的,但是修改的不是视图,修改的是视图映射的原表数据。
Ps:能改,但是别改。记住,视图就是用来查询的,别用于写操作。
11.5 删除视图
删除视图跟删除表一样。
语法:drop view 视图名;
# 删除视图 drop view v_emp_salary_gt_fivethousand;
十二、同义词(了解)
MySQL不支持同义词synonym这个关键字。
Oracle中支持synonym的构建。
在Oracle中是给对应的表,视图,存储过程起个别名,访问起来更方便一些。
因为在MySQL8.0中,提供了一个构建同义词数据库的存储函数。
将一些名字比较恶心的数据库,起个别名,用于做一些查询操作。
语法:call sys.create_synonym_db('原库','同义词库');
# 给test库搞一个同义词 call sys.create_synonym_db('test','t');构建完毕之后,会出现一个t数据库,在t数据库中,会将test库中的所有表和视图,全部生成为视图存户到t库中。
构建完毕同义词库中的视图,如果你做了修改和删除数据的操作,那修改和删除的是原库中的数据。
不过删除视图无所谓,视图删除了,和原表没关系。
十三、索引
索引可以提升查询是的效率。(合理的运用)
索引是给表中具体的列追加一个索引。
索引并不是什么列都适合添加的。
一般需要对经常被查询的列添加索引,而且这个列的值不能过于重复。
如果列的长度特别大的就不太适合添加索引。
查看表中的索引信息。
语法:show index from 表名;
通过上述语句,查看一下t_employees表中的索引信息
添加索引信息
语法:create [索引类型] index 索引名称 on 表名(列);
给员工表中的手机号字段,追加上一个普通索引。
# 给员工表中的手机号字段,追加上一个普通索引。 create index index_emp_phone on t_employees(phone_number);
给员工表中的邮箱字段追加一个唯一索引。
# 给员工表中的邮箱字段追加一个唯一索引。 create unique index index_unique_emp_email on t_employees(email);
经常有一种操作,在查询某张表时,经常用这种条件where a = ? and b = ? ……
这种查询可以做一个优化,可以将a列和b列创建一个联合(复合、多列)索引。
语法:create [索引类型] index 索引名称 on 表名(列1,列2);
这种联合索引的查询效率,比起单独给列1和列2分别构建索引的查询效率要快。
将员工表中的first_name和last_name组合一个联合索引。
# 将员工表中的first_name和last_name组合一个联合索引。 create index index_emp_name on t_employees(first_name,last_name);
删除索引操作。
语法:drop index 索引名称 on 表;
将员工表中的email的唯一索引删除掉。
# 将员工表中的email的唯一索引删除掉。 drop index index_unique_emp_email on t_employees;
创建表的时候,也可以指定索引信息(了解一小下)
语法:
create table 表名( 列1 数据类型…………, index(列名) # 构建索引的方式 );
十四、综合练习
后期针对MySQL的操作,其实90%以上都是做Select查询操作。
现在就用Oracle提供的三张经典表来做练习
emp(员工表)、dept(部门表)、salgrade(工资等级表)
14.1 外键约束的补充(了解)
在做真正的练习之前,优先搞定一下之前一致没聊的外键约束。
外键其实就是做表与表之前关联的一个约束。
现在有员工表,也有部门表。
一个部门下可以有多个员工。
一个员工只能属于一个部门。
就需要在一得一方,也就是员工表中,有一个外键,也就是deptno这个列,他的作用是和dept部门表做一个关联。当然,也可以给这个员工表中的deptno追加一个外键约束(不推荐)。
也给emp额外追加上外键约束。
语法:alter table 表名1 add constraint 外键名称 foreign key (列1) references 表名2(列2);
# 给员工表追加上deptno的外键约束 alter table emp add constraint fk_emp_dept foreign key (deptno) references dept(deptno);
14.2 查询操作练习
14.2.1 查询每个部门最高薪水的人员名称
需要查询的内容都处于员工表中。
需要查询员工的名称,部门,薪资。
首先先完成查询每个部门的最高薪资。 需要利用聚合函数的max,并且对部门编号做一个分组。
然后将部门最高信息查询返回的虚拟表与emp表做表连接,查询出最终结果
# 首先先完成查询每个部门的最高薪资。 需要利用聚合函数的max,并且对部门编号做一个分组。 select deptno,max(sal) as maxsal from emp group by deptno; # 将前面查询到的部门最高薪资,和当前的emp表做一个表连接操作,查询出每个部门薪资最高的员工名称 select e.ename,e.deptno,m.maxsal from emp e inner join (select deptno,max(sal) as maxsal from emp group by deptno) m on e.deptno = m.deptno and e.sal = m.maxsal;
14.2.2 查询哪些员工薪资在部门的平均薪资之上
首先,依然还是在员工表中查询。
需要查询员工名称,员工薪资,部门编号,部门平均薪资
首先需要先将各个部门的平均薪资查询出来,根据聚合函数avg以及对部门编号分组查询。
然后将查询的平均薪资和员工表做一个关联。
-- 查询哪些员工薪资在部门的平均薪资之上 -- 需要查询员工名称,员工薪资,部门编号,部门平均薪资 # 首先需要先将各个部门的平均薪资查询出来,根据聚合函数avg以及对部门编号分组查询。 select deptno,avg(sal) avgsal from emp group by deptno; # 将员工表和上述查询部门平均薪资的表关联到一起,条件是部门编号一致 and 员工薪资大于平均薪资 select e.ename,e.sal,e.deptno,a.avgsal from emp e inner join (select deptno,avg(sal) avgsal from emp group by deptno) a on e.deptno = a.deptno and e.sal > a.avgsal;
14.2.3 查询每个部门的平均薪资等级
首先这里需要查询员工表和薪资等级表。
需要查询部门编号以及部门的平均薪资等级
首先需要查询所有员工的薪资等级是多少。
直接将上述的查询结果作为一个from的虚拟表,直接对部门做分组,针对薪资等级做avg平均值即可
-- 查询每个部门的平均薪资等级 -- 需要查询部门编号以及部门的平均薪资等级 # 首先需要查询所有员工的薪资等级是多少。 select e.deptno,s.grade from emp e inner join salgrade s on e.sal between s.losal and hisal # 可以将上述的查询结果,基于deptno做分组,然后将grade做一个avg算平均数。 select es.deptno,avg(es.grade) from (select e.deptno,s.grade from emp e inner join salgrade s on e.sal between s.losal and hisal) es group by deptno;
14.2.4 查询平均薪资最高的部门名称
首先需要查询员工表和部门表
需要查询出来部门的名称和平均薪资
首先平均薪资单独的emp表就可以查询出来,再基于排序和limit,就可以只查询出平均薪资最高的部门
然后将上述查询结果的内容,和dept表做表连接,查询出薪资最高的部门信息
-- 查询平均薪资最高的部门名称 -- 需要查询出来部门的名称和平均薪资 # 首先平均薪资单独的emp表就可以查询出来,再基于排序和limit,就可以只查询出平均薪资最高的部门 select deptno,avg(sal) as avgsal from emp group by deptno order by avgsal desc limit 1 # 基于上述查询的结果,和dept表做一个表连接操作 select d.dname,da.avgsal from dept d inner join (select deptno,avg(sal) as avgsal from emp group by deptno order by avgsal desc limit 1) da on d.deptno = da.deptno;上述SQL可以查询出emp,dept表中的正确结构,但是如果多个部门的平均薪资一致,并且都是最高薪资,那上述查询就有问题了。
上述的limit方式不太合适了。
第一步:查询出平均薪资的最大值。
第二步:查询出和平均薪资最大值一致的部门编号。
第三部:基于部门编号查询出部门的名称。
# 上述的limit看着不错,但是存在问题。 # 第一步:查询出平均薪资的最大值。 select avg(sal) as avgsal from emp group by deptno order by avgsal desc limit 1; # 第二步:查询出和平均薪资最大值一致的部门编号。 select deptno,avg(sal) as maxavgsal from emp group by deptno having maxavgsal = (select avg(sal) as avgsal from emp group by deptno order by avgsal desc limit 1); # 第三部:基于部门编号查询出部门的名称。 select d.dname,avg(sal) as maxavgsal from emp e inner join dept d on e.deptno = d.deptno group by d.dname having maxavgsal = (select avg(sal) as avgsal from emp group by deptno order by avgsal desc limit 1);
14.2.5 查询薪水比自己领导还高的员工信息。
首先需要查询emp表,但是需要两张emp一个作为普通员工信息,一个作为领导信息
查询员工名称和员工薪资,领导名称和领导薪资
直接将两张emp表做连接,连接的条件是员工表中的mgr,与领导表中的empno作为条件。
-- 查询薪水比自己领导还高的员工信息。 -- 查询员工名称和员工薪资,领导名称和领导薪资 # 直接将两张emp表做连接,连接的条件是员工表中的mgr,与领导表中的empno作为条件。 select e.ename,e.sal,me.ename,me.sal from emp e inner join emp me on e.mgr = me.empno where e.sal > me.sal;
14.2.6 查询比普通员工的最高薪资还要高的领导名称
首先查询的依然是emp表。
查询出领导的名称和薪资即可。
要先分出来哪些是普通员工,哪些是领导。 领导的empno都在mgr字段上。
分成三步查询。
1、先查询出所有的领导的empno,只需要查询mgr字段即可,做个去重。
2、再基于上面查询出来的领导的empno,筛选出普通员工,查询出普通员工中的最高薪资。
3、再查询领导信息,薪资大于普通员工的最高薪资的领导信息查询出来。
-- 查询比普通员工的最高薪资还要高的领导名称 -- 1、先查询出所有的领导的empno,只需要查询mgr字段即可,做个去重。 select distinct mgr from emp where mgr is not null; -- 2、再基于上面查询出来的领导的empno,筛选出普通员工,查询出普通员工中的最高薪资。 select max(sal) as maxsal from emp where empno not in (select distinct mgr from emp where mgr is not null); -- 3、再查询领导信息,薪资大于普通员工的最高薪资的领导信息查询出来。 select ename,sal from emp where empno in (select distinct mgr from emp where mgr is not null) and sal > (select max(sal) as maxsal from emp where empno not in (select distinct mgr from emp where mgr is not null));
14.2.7 查询每个薪资等级有多少个员工
首先必然需要查询员工表以及薪资等级表的关联操作。
查询出薪资等级和对应的员工个数即可。
分成两步操作:
1、先基于emp和salgrade表查询出每位员工的薪资等级
2、在上述的基础上,再根据grade字段进行分组,查询count即可。
-- 查询每个薪资等级有多少个员工 # 1、先基于emp和salgrade表查询出每位员工的薪资等级 select e.ename,s.grade from emp e inner join salgrade s on e.sal between s.losal and s.hisal; # 2、在上述的基础上,再根据grade字段进行分组,查询count即可。 select s.grade,count(1) from emp e inner join salgrade s on e.sal between s.losal and s.hisal group by s.grade order by s.grade;
14.2.8 查询出入职时间早于其领导的员工信息和部门信息
首先需要查询emp表两张,同时还要查询出对应的部门信息,还要关联部门表。
需要查询出员工名称,部门名称,领导名称,领导部门
分成两步操作:
1、查询出员工及其领导信息,并且追加上一个判断,员工的入职时间,要早于领导的入职时间
2、再上述的基础上,再额外关联两张部门表,查询出对应的部门名称即可。
-- 查询出入职时间早于其领导的员工信息 # 需要查询出员工名称,部门名称,领导名称,领导部门 # 1、查询出员工及其领导信息,并且追加上一个判断,员工的入职时间,要早于领导的入职时间 select e.ename 员工名称,m.ename 领导名称 from emp e inner join emp m on e.mgr = m.empno where e.hiredate < m.hiredate; # 2、再上述的基础上,再额外关联两张部门表,查询出对应的部门名称即可。 select e.ename 员工名称,d.dname 员工部门,m.ename 领导名称 ,md.dname 领导部门 from emp e inner join emp m on e.mgr = m.empno inner join dept d on e.deptno = d.deptno inner join dept md on m.deptno = md.deptno where e.hiredate < m.hiredate;
14.2.9 查询出至少有5位员工的部门信息
首先需要查询emp和dept表,需要两张表做一个关联。
需要查询部门的编号,部门的名称,部门的员工人数。
分成两步走:
1、关联员工和部门表,查询出部门信息和部门的员工人数。
2、在上述的基础上,筛选出员工人数大于5个的部门信息。
-- 查询出至少有5位员工的部门信息 # 需要查询部门的编号,部门的名称,部门的员工人数。 # 分成两步走: # 1、关联员工和部门表,查询出部门信息和部门的员工人数。 select d.deptno,d.dname,count(1) from emp e inner join dept d on e.deptno = d.deptno group by d.deptno; # 2、在上述的基础上,筛选出员工人数大于5个的部门信息。 select d.deptno,d.dname,count(1) as empcount from emp e inner join dept d on e.deptno = d.deptno group by d.deptno having empcount >= 5
14.2.10 查询出薪资高于公司薪资的平均水平的员工名称,所在部门,上级领导名称,员工名称的薪资等级
首先这里需要所有表都参与。emp表查询出员工和领导的信息,所在部门需要dept表,员工薪资水平需要salgrade表。
需要查询员工名称,所在部门,上级领导名称,员工名称的薪资水平
分成四步走:
1、查询出员工信息和所在部门的信息。
2、在上述的基础上筛选出薪资高于公司平均水平的员工。
3、在上述的基础上再追加查询员工的领导名称。
4、在上述的基础上,再追加查询员工的薪资水平。
-- 查询出薪资高于公司薪资的平均水平的员工名称,所在部门,上级领导名称,员工名称的薪资水平 # 需要查询员工名称,所在部门,上级领导名称,员工名称的薪资水平 # 分成四步走: # 1、查询出员工信息和所在部门的信息。 select e.ename,d.dname from emp e inner join dept d on e.deptno = d.deptno; # 2、在上述的基础上筛选出薪资高于公司平均水平的员工。 select e.ename,d.dname from emp e inner join dept d on e.deptno = d.deptno where e.sal > (select avg(sal) from emp); # 3、在上述的基础上再追加查询员工的领导名称。 select e.ename 员工名称,d.dname 员工部门, m.ename 领导名称 from emp e inner join dept d on e.deptno = d.deptno left join emp m on e.mgr = m.empno where e.sal > (select avg(sal) from emp); # 4、在上述的基础上,再追加查询员工的薪资水平。 select e.ename 员工名称,d.dname 员工部门, m.ename 领导名称,s.grade 员工薪资等级 from emp e inner join dept d on e.deptno = d.deptno left join emp m on e.mgr = m.empno inner join salgrade s on e.sal between s.losal and s.hisal where e.sal > (select avg(sal) from emp);
14.2.11 查询与'SCOTT'从事相同工作的员工名称和部门名称
首先需要查询emp和dept的关联查询,同时需要子查询来找到'SCOTT'的工作作为条件筛选的值
需要查询员工名称和部门名称
分成两步走
1、正常的查询出员工的名称和所在的部门
2、基于'SCOTT'从事的工作筛选出对应的员工信息
-- 查询与'SCOTT'从事相同工作的员工名称和部门名称 # 需要查询员工名称和部门名称 # 分成两步走 # 1、正常的查询出员工的名称和所在的部门 select e.ename,d.dname from emp e inner join dept d on e.deptno = d.deptno; # 2、基于'SCOTT'从事的工作筛选出对应的员工信息 select e.ename,d.dname from emp e inner join dept d on e.deptno = d.deptno wheree.job = (select job from emp where ename = 'SCOTT') and ename != 'SCOTT';
14.2.12 查询没有员工的部门信息(exists)
首先,查询时其实依然是emp和dept表之间的一个联系。需要查询出员工表中不存在的deptno,但是dept表存在的部门信息。
exists是可以追加到条件里的。
语法:where exists (查询)
上述语法中,如果 (查询) 有结果,相当于条件满足,会返回当前数据,如果 (查询) 没有结果,相当于不满足条件,不会返回当前结果。
在exists前,可以追加not,效果就是取反的效果了。
可以在查询部门时,基于emp表的查询结合exists来做到,如果查询有员工信息,返回true,不返回当前结果,如果返回false,希望返回结果。
select d.deptno,d.dname,d.loc from dept d where not exists (select empno from emp e where e.deptno = d.deptno);
14.2.13 查询部门的平均薪资,以2000作为点,返回'大于2000'或者'小于2000'或者'等于2000'的结果
首先查询平均薪资,必然会用到员工表和部门表两个信息。
查询部门编号,以及部门的薪资导致是大于,小于,等于2000的结果。
需要使用到case when then end这种操作。
分成两步操作
1、查询每个部门的平均薪资。
2、基于上述查询,将平均薪资的返回结果替换为需求中的大于,小于,等于2000的结果。
-- 查询部门的平均薪资,以2000作为点,返回'大于2000'或者'小于2000'或者'等于2000'的结果 # 查询部门编号,以及部门的薪资导致是大于,小于,等于2000的结果。 # 分成两步操作 # 1、查询每个部门的平均薪资。 select d.deptno, avg(e.sal) from emp e inner join dept d on e.deptno = d.deptno group by d.deptno; # 2、基于上述查询,将平均薪资的返回结果替换为需求中的大于,小于,等于2000的结果。 select d.deptno, avg(e.sal) 平均薪资, case when avg(e.sal) = 2000 then '等于2000'when avg(e.sal) > 2000 then '大于2000'else '小于2000' end as 是否大于2000 from emp e inner join dept d on e.deptno = d.deptno group by d.deptno;