將兩個表或者兩個以上的表以一定的連接條件連接起來,從中檢索出滿足條件的數據。
內連接
使用inner join
,inner
可以省略
-- 查詢員工的姓名和部門名稱
select "E".ename as "員工姓名", "D".dname as "部門名稱"from emp "E"join dept "D"on "E".deptno = "D".deptno
select … from A, B
假設A表有xxx行,則行可以表示為集合(a1,a2,...,ax)(a_1,a_2,...,a_x)(a1?,a2?,...,ax?)
假設B表有yyy行,則行可以表示為集合(b1,b2,...,by)(b_1,b_2,...,b_y)(b1?,b2?,...,by?)
則select ... from A,B
就是將兩個表的行進行笛卡爾成績,并將兩個行進行合并得到(a1+b1,a1+b2,...,a2+b1,a2+b2,...)(a_1+b_1,a_1+b_2,...,a_2+b_1,a_2+b_2,...)(a1?+b1?,a1?+b2?,...,a2?+b1?,a2?+b2?,...),因此總共的行數是x?yx*yx?y,總共的列數是兩個表列數相加
即把A表的每一條記錄都和B表的每一條記錄組合在一起
select … from A,B where …
對上面的表用where
的條件進行過濾
select E.ename as "員工姓名", D.dname as "部門名稱"from emp as "E", dept as "D"where E.deptno = D.deptno
select … from A join B on …
join
是連接的意思 on
表示連接條件
如果使用join
就必須使用on
select * from empjoin depton 1=1 --70*11select emp.ename as '員工姓名', dept.deptno as '部門編號'from empjoin depton 1 = 1 --70*2select emp.ename as '員工姓名', dept.deptno as '部門編號'from empjoin depton emp.deptno=dept.deptno --14*2select E.ename as '員工姓名', D.deptno as '部門編號'from emp as "E"join dept as "D"on E.deptno=D.deptno --14*2
select *from emp as "E"join dept as "D"on 1 =1 select *from dept as "D"join emp as "E"on 1 =1 order by D.deptnoselect * from dept,emp
where dept.deptno = emp.deptno
--實際中發現無論將哪個表放在前面,總是用行數少的表匹配行數多的
from
和join
后面可以使用別名,如果在這里使用別名,其他的地方也都必須使用別名。區別于select
后面的別名不能在其他地方使用,我認為根本原因在于語句的執行順序
實際上和select ... from A,B where ...
等價,推薦使用join on
使用join on
可以再使用where
對得到的數據過濾,從而實現不同的分工
混合使用
select * from emp as "E", dept as "D"
where E.deptno=D.deptno and E.sal>2000
--等價于下面的寫法,下面的寫法更加清晰
select * from emp as "E"join dept as "D"on E.deptno = D.deptnowhere E.sal > 2000--求出工資大于2000的員工的姓名 部門編號 薪水 薪水等級
select emp.ename as "員工姓名", dept.dname as "部門名稱", emp.sal as "薪水", SALGRADE.GRADE as "薪水等級"from emp,dept,SALGRADEwhere emp.deptno=dept.deptno and emp.sal>2000 and emp.sal >= SALGRADE.LOSAL and emp.sal <=SALGRADE.HISALselect emp.ename as "員工姓名", dept.dname as "部門名稱", emp.sal as "薪水", SALGRADE.GRADE as "薪水等級"from empjoin depton emp.deptno=dept.deptnojoin SALGRADEon emp.sal>=SALGRADE.LOSAL and emp.sal<=SALGRADE.HISALwhere emp.sal>2000
我們也可以把查詢的表當作一個表,進行子查詢
-- 輸出部門名稱,該部門所有員工的平均工資 平均工資等級select dept.dname as "部門名稱", tmp.avg_sal as "平均工資", SALGRADE.GRADE as "平均工資等級"from(select emp.deptno as "dept_no", AVG(emp.sal) as "avg_sal"from empgroup by emp.deptno) "tmp"join depton dept.deptno = tmp.dept_nojoin SALGRADEon tmp.avg_sal between SALGRADE.LOSAL and SALGRADE.HISAL
語句順序
SELECT ...INTOFROMJOINONWHEREGROUP BYHAVINGORDER BY
-- 輸出3個姓名中不含有O的工資最高的員工的姓名、工資、工資等級、部門名稱select top 3 emp.ename as "員工姓名", emp.sal as "員工工資", SALGRADE.GRADE as "工資等級", dept.dname as "部門名稱"from empjoin depton emp.deptno=dept.deptnojoin SALGRADEon emp.sal >= SALGRADE.LOSAL and emp.sal <= SALGRADE.HISALwhere emp.ename not like '%O%'order by emp.sal desc
當null
和not in
在一起的時候需要注意。如果表中有null
,則使用not in
的時候返回的總為空。
這與SQL的比較機制有關。在SQL中比較結果分為true``false``null
,只有結果為true
的時候系統才認為匹配成功并返回記錄,in
的本質是等于的or
,not in
的本質是不等于的and
。
比較結果 | and null | or null |
---|---|---|
true | null | true |
false | false | null |
null | null | null |
當使用in
的時候因為是or
進行連接,所以可以正常返回true
,在not in
的時候是and
連接,因此返回總為null
,因此返回為空。
詳細原因可以看這篇文章:傳送門。為了解決這個問題我們可以使用is [not] null
和isnull()
函數組合判斷
--求出emp表中所有領導的姓名select distinct E1.ename as "領導姓名"from emp "E1"join emp "E2"on E1.EMPNO = E2.mgrselect emp.ename as "領導姓名"from empwhere emp.EMPNO in (select distinct mgr from emp)--輸出所有非領導的信息select *from empwhere emp.EMPNO not in (select distinct mgr from emp where mgr is not null)
--求出平均薪水最高的部門的名稱和部門平均工資select dept.dname as "部門名稱", tmp.avg_sal as "平均工資"from (select top 1 emp.deptno as "dept_no", AVG(emp.sal) as avg_salfrom empgroup by emp.deptnoorder by AVG(emp.sal) desc) "tmp"join depton tmp.dept_no=dept.deptno
當子查詢的值只有一個的時候可以將子查詢放在表達式中
--工資大于 所有員工中工資最低的人中的工資 的人中
--前三個人的姓名 工資 部門編號 部門名稱 工資等級
select top 3 emp.ename as "姓名", emp.sal as "工資", emp.deptno as "部門編號", dept.dname as "部門名稱", SALGRADE.GRADE as "工資等級"from empjoin (select MIN(sal) as "min_sal" from emp) as "tmp"on emp.sal > tmp.min_saljoin dept on emp.deptno = dept.deptnojoin SALGRADEon emp.sal between SALGRADE.LOSAL and SALGRADE.HISALorder by emp.sal select top 3 tmp.ename as "姓名", tmp.sal as "工資", tmp.deptno as "部門編號", dept.dname as "部門名稱", SALGRADE.GRADE as "工資等級"from ( select ename,sal,deptno from emp where sal > (select MIN(sal) as "min_sal" from emp)) as "tmp"join dept on tmp.deptno = dept.deptnojoin SALGRADEon tmp.sal between SALGRADE.LOSAL and SALGRADE.HISALorder by tmp.sal
--把工資大于1500的所有員工按部門分組,
--按升序輸出最后兩個平均工資小于3000的部門名稱,人數,平均工資,平均工資水平
select dept.dname as "部門名稱", tmp.number as "部門人數", tmp.avg_sal as "平均工資", SALGRADE.GRADE as "平均給工資水平"from(select top 2 deptno as "dept_no", COUNT(*) as "number", AVG(sal) as "avg_sal"from emp where sal>1500 group by deptnohaving AVG(sal)<3000order by AVG(sal) desc) "tmp"join depton tmp.dept_no=dept.deptnojoin SALGRADEon tmp.avg_sal between SALGRADE.LOSAL and SALGRADE.HISALorder by tmp.avg_sal
order by
的順序應該在最后,因此可以用別名。group by
和having
都不可以用別名
外連接
不但返回滿足條件的所有記錄,而且會返回部門不滿足條件的記錄。
左外連接
select * from empleft join depton emp.deptno=dept.deptno
- 用左表的一行分別和右表的所有行進行連接,如果沒有匹配的行,則一起輸出,如果右表有多行匹配,則結果輸出多行。如果沒有匹配行,則結果只輸出一行,該輸出左邊為左表的一行的內容,右邊全部輸出
null
- 因為右邊很可能出現有多行和左表的某一行匹配,所以左連接產生的結果集的行數很可能大于左邊表的行數
select * from deptleft join empon dept.deptno=emp.deptno --16行
返回一個事物和該事物的相關信息,如果沒有相關信息,就輸出空
右外連接
同左外連接
完全連接
full join
- 兩個表中匹配的所有行記錄
- 左表中那些在右表找不到匹配的行的記錄,右邊為
NULL
- 右表中那些在左表找不到匹配的行的記錄,左邊為
NULL
交叉連接
cross join
等價于join on 1=1
,后面不用加on
自連接
一張表和自己連接起來,注意連接自己的時候需要標明是哪一張表中的字段
--求薪水最高的員工的信息select *from empwhere sal = (select MAX(sal) from emp)-- 不準用聚合函數,求薪水最高的員工的信息
select *from empjoin (select top 1 EMPNO from emp order by sal desc) "tmp"on emp.EMPNO=tmp.EMPNOselect *from empwhere sal not in (select distinct E1.salfrom emp as "E1"join emp as "E2"on E1.sal < E2.sal)
聯合
縱向連接表中的數據,即添加一行
--輸出每個員工的姓名,工資,上司的姓名select E1.ename as "姓名", E1.sal as "工資", E2.ename as "上司"from emp as "E1"left join emp as "E2" --用左連接的原因是有一個沒有上司on E1.mgr = E2.EMPNO--或者使用聯合select E1.ename as "姓名", E1.sal as "工資", E2.ename as "上司"from emp as "E1"join emp as "E2"on E1.mgr = E2.EMPNO
union
select ename, sal, 'BOSS' from emp where mgr is null
注意:
select
子句輸出列數相等- 數據類型也相同,至少是兼容的