SQL Server【三】连接查询
將兩個表或者兩個以上的表以一定的連接條件連接起來,從中檢索出滿足條件的數(shù)據(jù)。
內(nèi)連接
使用inner join,inner可以省略
-- 查詢員工的姓名和部門名稱 select "E".ename as "員工姓名", "D".dname as "部門名稱"from emp "E"join dept "D"on "E".deptno = "D".deptnoselect … from A, B
假設(shè)A表有xxx行,則行可以表示為集合(a1,a2,...,ax)(a_1,a_2,...,a_x)(a1?,a2?,...,ax?)
假設(shè)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?,...),因此總共的行數(shù)是x?yx*yx?y,總共的列數(shù)是兩個表列數(shù)相加
即把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.deptnoselect … from A join B on …
join是連接的意思 on 表示連接條件
如果使用join就必須使用on
from和join后面可以使用別名,如果在這里使用別名,其他的地方也都必須使用別名。區(qū)別于select后面的別名不能在其他地方使用,我認(rèn)為根本原因在于語句的執(zhí)行順序
實際上和select ... from A,B where ...等價,推薦使用join on
使用join on可以再使用where對得到的數(shù)據(jù)過濾,從而實現(xiàn)不同的分工
混合使用
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我們也可以把查詢的表當(dāng)作一個表,進行子查詢
-- 輸出部門名稱,該部門所有員工的平均工資 平均工資等級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當(dāng)null和not in在一起的時候需要注意。如果表中有null,則使用not in的時候返回的總為空。
這與SQL的比較機制有關(guān)。在SQL中比較結(jié)果分為true``false``null,只有結(jié)果為true的時候系統(tǒng)才認(rèn)為匹配成功并返回記錄,in的本質(zhì)是等于的or,not in的本質(zhì)是不等于的and。
| true | null | true |
| false | false | null |
| null | null | null |
當(dāng)使用in的時候因為是or進行連接,所以可以正常返回true,在not in的時候是and連接,因此返回總為null,因此返回為空。
詳細原因可以看這篇文章:傳送門。為了解決這個問題我們可以使用is [not] null和isnull()函數(shù)組合判斷
--求出emp表中所有領(lǐng)導(dǎo)的姓名select distinct E1.ename as "領(lǐng)導(dǎo)姓名"from emp "E1"join emp "E2"on E1.EMPNO = E2.mgrselect emp.ename as "領(lǐng)導(dǎo)姓名"from empwhere emp.EMPNO in (select distinct mgr from emp)--輸出所有非領(lǐng)導(dǎo)的信息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當(dāng)子查詢的值只有一個的時候可以將子查詢放在表達式中
--工資大于 所有員工中工資最低的人中的工資 的人中 --前三個人的姓名 工資 部門編號 部門名稱 工資等級 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的部門名稱,人數(shù),平均工資,平均工資水平 select dept.dname as "部門名稱", tmp.number as "部門人數(shù)", 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_salorder by的順序應(yīng)該在最后,因此可以用別名。group by和having都不可以用別名
外連接
不但返回滿足條件的所有記錄,而且會返回部門不滿足條件的記錄。
左外連接
select * from empleft join depton emp.deptno=dept.deptno- 用左表的一行分別和右表的所有行進行連接,如果沒有匹配的行,則一起輸出,如果右表有多行匹配,則結(jié)果輸出多行。如果沒有匹配行,則結(jié)果只輸出一行,該輸出左邊為左表的一行的內(nèi)容,右邊全部輸出null
- 因為右邊很可能出現(xiàn)有多行和左表的某一行匹配,所以左連接產(chǎn)生的結(jié)果集的行數(shù)很可能大于左邊表的行數(shù)
返回一個事物和該事物的相關(guān)信息,如果沒有相關(guān)信息,就輸出空
右外連接
同左外連接
完全連接
full join
- 兩個表中匹配的所有行記錄
- 左表中那些在右表找不到匹配的行的記錄,右邊為NULL
- 右表中那些在左表找不到匹配的行的記錄,左邊為NULL
交叉連接
cross join等價于join on 1=1,后面不用加on
自連接
一張表和自己連接起來,注意連接自己的時候需要標(biāo)明是哪一張表中的字段
--求薪水最高的員工的信息select *from empwhere sal = (select MAX(sal) from emp)-- 不準(zhǔn)用聚合函數(shù),求薪水最高的員工的信息 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)聯(lián)合
縱向連接表中的數(shù)據(jù),即添加一行
--輸出每個員工的姓名,工資,上司的姓名select E1.ename as "姓名", E1.sal as "工資", E2.ename as "上司"from emp as "E1"left join emp as "E2" --用左連接的原因是有一個沒有上司on E1.mgr = E2.EMPNO--或者使用聯(lián)合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子句輸出列數(shù)相等
- 數(shù)據(jù)類型也相同,至少是兼容的
分頁查詢
總結(jié)
以上是生活随笔為你收集整理的SQL Server【三】连接查询的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 少精症治疗费用大概要多少钱
- 下一篇: SQL Server【四】