连接查询及SQL执行顺序简单梳理

一、联合

       UNION即表和表之间的数据以纵向的方式联合到一起,本篇博客下面要讲的连接都是以横向的方式联合到一起,注意区分。

       那Mysql既然不支持完全连接,那完全可以通过联合(UNION)和外连接达到完全连接查询的目的。





二、内连接

1、多表查询+where

       先要搞清楚select * from A, B返回的结果到底是什么?—返回的行数是A表与B表记录的乘积列数是两表列数之和。而且A和B的顺序无关紧要,不写过滤条件的话,默认就是将表A中的每一条记录都与表B中的每一条记录进行组合,或者说是将表B中的每一条记录都和表A中的每一条记录进行组合。

select * from A, B == select * from B, A == select * from A, B where 1=1

       从多表中查询并且通过where过滤数据(加上连接条件)其实也是一种内连接了。

       注意:如果两张关联表中有两列名字相同,需用表名.列名加以区分,否则会报错!

	select * from emp, dept					//表的顺序也不重要
		where emp.emp_dept_id=dept_id		//相等条件也可以互换位置
		order by emp_salary desc;

Alt

       当用where进行内连接时,需要将外键表的外键和主键表的主键关联起来才能完成内连接,否则只是瞎组合。



2、join on

	select * from emp
		join dept
		on 1=1;
	//运行结果和用where做内连接不写条件一样

       mysql默认就是内连接即join a on == inner join a on(只抽取公共部分)。

Alt

       Mysql使用join连接表的时候不写on(连接条件)竟然也不会报错。。。垃圾。。。

	select * from emp
		join dept
		on emp_dept_id=dept_id;

       这才是两张表的成功连接。

       注意:where条件必须写在join on之后!内连接时候的on既可以写连接条件也可以写过滤条件。





三、外连接

       外连接时候,先出现的表在左边后出现的表在右边

1、左外连接

	select * from emp	
		left join dept
		on emp_dept_id=dept_id;
	//将emp表左外连接到dept表上

       以上面的sql语句说明,相当于emp表中每一条数据都要从dept表中寻找匹配的记录,如果dept表中能匹配上就整体输出,dept表中匹配不上的就输出左边(emp),右边(dept)都为null以左边的表为基准---右边可为空。

       注意:外连接时候on只能用作连接的条件,其他过滤条件需要放到where中,这点和内连接不同。

譬如:

	select * from emp	
		left join dept
		on emp_dept_id=dept_id and emp_id=3;

Alt

       外连接的时候用on过滤数据的时候,机制猜测是先选择临时表中的所有行,再根据是左连接还是右连接进行过滤。如果是左连接,on中连接条件后面的过滤条件会针对右边的表进行过滤,符合条件右边表就原样输出,不符合条件右边表则为空;如果是右连接,on中连接条件后面的过滤条件会针对左边的表进行过滤,符合条件左边表就原样输出,不符合条件左边表则为null。本质也是以左边表为基准---右边可为空。

重新用两张表举例子:
Alt
Alt

	SELECT * FROM student st
		LEFT JOIN school sl 
		ON sl.sl_id=st.school_id

Alt



2、右外连接

       以右边的表为基准---左边可为空。

	SELECT * FROM student st
		RIGHT JOIN school sl 
		ON sl.sl_id=st.school_id;

Alt




四、完全连接

       既已右边为基准,又以左边为基准。

       Mysql不支持。转换思路,使用两次外连接加联合解决。

	SELECT * FROM student st
		LEFT JOIN school sl 
		ON sl.sl_id=st.school_id
	UNION
		SELECT * FROM student st
		RIGHT JOIN school sl 
		ON sl.sl_id=st.school_id;

Alt




五、交叉连接

       交叉结果的行数是两表行数的乘积,列数是两表列数之和。

	select * from emp
		cross join dept;
		
	//等价于
	select * from emp dept;




六、自连接

       举个很简单的例子,查询所有工资比王五高的员工的姓名及工资。

	select emp_name, emp_salary from emp 
		where emp_salary>(
				select emp_salary from emp
					where emp_name='王五'
				);

Alt




七、例子

       1、找出姓名不包含王的所有员工中工资最高的前3名的每个员工的姓名、工资、工资等级、部门名称。

	select emp_name, emp_salary, sal_level, dept_name from emp
		join dept 
		on dept_id=emp_dept_id
		join salgrade
		on emp_salary between sal_low and sal_high
		where emp_name not like '%王%' 
		order by emp_salary desc
		limit 0, 3;

Alt

       2、求出每个员工的姓名、部门编号、薪水和薪水的等级。

	select emp_name, emp_dept_id, emp_salary, sal_level from emp
		join salgrade
		on emp_salary between sal_low and sal_high;
	

Alt

       3、查找每个部门的编号、该部门所有员工的平均工资以及平均工资的等级。

	select T.emp_dept_id, T.avg_sal, S.sal_level from salgrade as S
		join (
			select emp_dept_id, avg(emp_salary) as avg_sal from emp
				group by emp_dept_id
		) as T
		on T.avg_sal between S.sal_low and S.sal_high
		order by T.emp_dept_id asc;

Alt

       Mysql要求嵌套查询的时候需要要给表取别名,否则会报错,给表取别名还不能加双引号???垃圾,列最好也别加双引号。。。。其实取别名的时候as关键字可以省略,加上可以增加可读性。


       4、查找每个部门的编号、部门名称、该部门所有员工的平均工资以及平均工资的等级。

	select T.emp_dept_id, D.dept_name, T.avg_sal, S.sal_level from salgrade as S
		join (
			select emp_dept_id, avg(emp_salary) as avg_sal from emp
				group by emp_dept_id
		) as T
		on T.avg_sal between S.sal_low and S.sal_high
		join dept as D
		on T.emp_dept_id=D.dept_id
		order by T.emp_dept_id asc;

Alt


       5、求出emp表中所有上级的信息。

	//典型的自连接查询
	select * from emp
		where emp_id in(select emp_manager_id from emp);

Alt

       要找出非上级信息就很简单了,直接not in解决。



       6、求出平均薪水最高的部门的编号和部门的平均工资。

	select emp_dept_id as "部门编号", avg(emp_salary) as "平均工资" from emp
		group by emp_dept_id
		order by avg(emp_salary) desc
		limit 0, 1;


       7、除掉工资最低的人后,剩下的人中工资最低的前3个人的姓名、工资、部门编号、部门名称、工资等级输出。

	select T.emp_name, T. emp_salary, D.dept_id, D.dept_name,S.sal_level from dept as D
		join (
			select * from emp
				where emp_salary>(select min(emp_salary) from emp)
		) as T
		on D.dept_id=T.emp_dept_id
		join salgrade as S
		on T.emp_salary between S.sal_low and S.sal_high
		order by T.emp_salary asc
		limit 0, 3;



八、SQL执行顺序梳理

Alt

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章