1. 关联查询

条件或者结果分布于多张表,连接多张表查询

1.1 内连接

内连接是将多张表都出现的记录连接展示在结果层

没有主从表之分,结果与连接顺序无关

select ename,sal,dname from emp,dept where emp.deptno = dept.deptno and empno = 7788;

# inner join ... on ...
select *from emp inner join dept on emp.deptno=dept.deptno;

# inner join ... using(字段)
select * from emp inner join dept using(deptno);
	*关联字段名字必须一致
	*将关联字段去除
	*必须使用在等值连接
1.2 自然连接

自然连接都是等值连接(将两张表 名称一样 值一样的记录进行关联),等值连接不一定是自然连接

select * from emp natural join dept;
1.3 外连接

以驱动表为基准(left 前 right后) 依次遍历并于夫鼠标建立连接;

如果在附属表中找到匹配记录就连接并展示;如果找不到则以null填充。

存在主从表之分,与连接顺序有关。

left [outer] join ... on ... : 左外连接
right [outer] join ... on ... : 右外连接
select * from dept left join emp on emp.deptno=dept.deptno;
1.4 自连接

自身连接自身

# 查询员工及其领导的姓名
select e1.ename,e2.ename from emp e1,emp e2 where e1.mgr=e2.empno;

2. 子查询

嵌套查询

2.1 子查询分类
# 单行子查询:子查询返回的结果是单行单列
	select dname from dept where deptno=(select deptno from emp where empno =7788);
# 多行子查询:子查询返货的结果是多行
	select dname from dept where deptno in (select distinct deptno from emp where sal >2000);
	any / all
	=any 相当于 in    >any:大于最小值			<any:小于最大值
					>all:大于最大值			 <all:小于最小值

练习

#1.查询30号部门中最高工资的员工信息(考虑并列)
	select * from emp where sal =(select max(sal) from emp where deptno=30) and deptno=30;
	
	#2.查询20号部门中工资次高的员工信息
	select * from emp where deptno=20 and sal = (select max(sal) from (select * from emp where deptno=20 and sal < any(select sal from emp where deptno=20)) emp2);
	
	#3.查询大于所在部门平均工资的员工信息
	
	# 关联查询
	# 分组求平均工资
	# 工资>平均工资
	
	select emp.* from emp,(select deptno ,avg(sal) avg from emp group by deptno) e where emp.deptno=e.deptno and emp.sal>e.avg;	
	
	# 子查询
	select * from emp e1 where sal>(select avg(sal) from emp e2 where e2.deptno=e1.deptno);
	
	
	# 查询工资>2000的员工所在部门名称
	select dname from dept where deptno in  (select deptno from emp where sal>2000)
	
	select dname from dept where exists (select * from emp where sal>2000 and emp.deptno=dept.deptno)
	
	in 和exists之间的区别:
	1. in 先执行子查询,将子查询的结果返回给主查询,由主查询继续检索;exists先执行主查询,将主查询的记录一次交给子查询,在子查询中进行匹配,如果匹配则返回true,并将主查询的结果显示在结果集,如果返回false则不展示。
	2.in 必须让主查询的条件字段和子查询的结果字段匹配;exists不关心子查询的返回结果。 
	
	选择:
	1.如果查询的结果分布于多张表,选择关联查询
	2.如果结果分布于一张表,关联查询和子查询都可以使用
	3.查询尽量不要过多的嵌套,理论上说尽可能使用关联查询代替子查询提升性能
	4.尽可能先过滤再关联

3.联合查询

union:去重
union all: 不去重

select * from emp where deptno = 20
union
select * from emp where sal > 2000;

联合查询多个结果集的字段信息需要一致。

4.事务

保证数据一致性。

又一系列的dml操作组成,要么同时成功,要么同时失败

在数据库中,任何的增删改操作都必须再事物的环境下运行。

# 开启事务
一组dml操作
# 提交/回滚事务

#查看事务的自动提交,默认开启
show variables like '%autocommit%'

如果事务的自动提交开启,默认会将每一个dml操作当作单独的事务进行处理

如果要将多个dml操作放到一个事务中处理:
1.关闭事务的自动提交
	set autocommit = 0;
2.手动开启事务
	begin; / start transaction;
3.一组dml操作
4.手动提交/回滚事务
	commit; (持久化数据到文件中)/ rollback;
  • 事务的四大特性
  • 原子性:同一事务中的dml作为整体不可分割
  • 一致性:事务执行前后整体的状态不变
  • 隔离性:并发事务之间独立的
  • 持久性:事务提交完成,数据应该持久化到数据库,不会随意发生改变
  • 并发事务会产生的问题
  • 脏读

t2事务读到 t1事务未提交的数据

  • 不可重复读

t2事务在可读范围内 t1事务修改了该数据并且进行了事务提交

t2在多次读取的过程中发现数据不一致

  • 幻读(虚读)

t2事务在可读范围内 t1事务删除记录并且进行了事务提交

t2在多次读取过程中发现数据数目不一致

  • 事务的隔离级别
  • 读未提交:不能解决任何并发问题
  • 读已提交:能够解决脏读问题(oracle)
  • 可重复度:解决 脏读和不可重复读(mysql)
  • 串行化: 解决所有问题

5. 存储程序

运行于服务器端程序

  • 存储过程:输入和输出参数
delimiter //;
create procedure sel_emp(dno int)
begin
	select * from emp where deptno=dno;
end //;
	
call sel_emp(10);

# 参数模式:
	in:默认,输入参数
	out:输出参数
	inout:输入输出参数
	
# 输入员工编号查询名称
delimiter //;
create procedure sel_ename(eno int,out name varchar(20))
begin
	select ename into name from emp where empno =eno;
end//;

call sel_ename(7788,@name);
select @name;
		
#根据名称获取职位
delimiter //;
create procedure sel_job(inout name_job varchar(20))
begin
	select job into name_job from emp where ename =name_job;
end//;

set @v_name='SCOTT';
call sel_job(@v_name);
select @v_name;

# 选择结构

#根据成绩分级
delimiter //;
create procedure score(score int)
begin
	#声明变量
	declare v_level varchar(20);
	if score >= 85 then
		set v_level ='A';
	elseif score >=60 then
		set v_level ='B';
	else 
		set v_level ='C';
	end if;
	select v_level;
end //;
call score(90);


# 循环结构

# whlie...do...end while
# 1+...+100
delimiter //;
create procedure calc()
begin
	declare i int;
	declare sum int;
	set i=1;
	set sum=0;
	
	while i<=100 do
		set sum =sum+i;
		set i= i+1;
	end while;
	select sum;
end //;
call calc();

# loop...end loop
delimiter //;
create procedure calc1()
begin
	declare i int;
	declare sum int;
	set i=1;
	set sum=0;
	
	lip:loop 
		if i>100 then
			leave lip;
		end if;
		set sum =sum+i;
		set i= i+1;
	end loop;
	select sum;
end //;
call calc1();

# repeat ... end repeat
delimiter //;
create procedure calc2()
begin
	declare i int;
	declare sum int;
	set i=1;
	set sum=0;
	
	repeat
		set sum =sum+i;
		set i= i+1;
		until i>100
	end repeat;
	select sum;
end //;
call calc2();
  • 存储函数:有返回值
  • 触发器:由事件驱动