連接查詢及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

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