Oracle多表關聯
1. 92語法多表關聯
1.1笛卡爾積
-- 笛卡爾積 select * from emp,dept
1.2等值連線
-- 等值連線 -- 需求:查詢僱員的部門名稱 select e.ename,e.deptno,d.dname from emp e,dept d where e.deptno = d.deptno
1.3不等值連線
-- 不等值連線 -- 查詢每個僱員的薪資等級 select e.ename,e.sal,sg.grade from emp e,salgrade sg where e.sal >= sg.losal and e.sal <= sg.hisal -- where e.sal between sg.losal and sg.hisal
1.4外連線
左外連線:左邊的表作為主表,右邊表作為從表,主表資料都顯示,從表資料沒有,用null填充,用+號表示。
-- 左外連線(B) -- 需求:查詢所有部門的僱員 select * from dept d,emp e where d.deptno = e.deptno(+)
右外連線: 右邊的表作為主表,左邊表作為從表,主表資料都顯示,從表資料沒有,用null填充,用+號表示。
-- 右外連線(B) select * from emp e,dept d where e.deptno(+) = d.deptno;
1.5自連線
-- 查詢每個僱員的上級領導 select e.ename "僱員",m.ename "領導" from emp e,emp m where e.mgr = m.empno -- 優化king select e.ename "僱員",nvl(m.ename,'boss') "領導" from emp e,emp m where e.mgr = m.empno(+)
1.6多餘兩張表的連線
如果有多個表參與查詢,先把t1xt2笛卡爾積得到一個大表T1,再把T1xt3笛卡爾積得到一個另外的大表T2,依次類推。
所有的多表查詢最終都是兩種表的查詢。
-- 查詢SCO%T管理者的薪資等級 select e.ename,m.ename,sg.grade from emp e,emp m,salgrade sg where e.mgr = m.empno and (m.sal between sg.losal and sg.hisal) and e.ename = 'SCO%T' -- 查詢僱員Scott所在部門名稱和薪資等級 select e.*,d.*,sg.* from emp e,dept d,salgrade sg where e.deptno = d.deptno and e.sal between sg.losal and sg.hisal and e.ename = 'SCO%T'
2.99語法多表關聯
92語法的主要問題:
[1]表的過濾條件和表的連線條件混合在一起,維護麻煩
[2]資料庫的資料適合變化,根據where子句的執行規則,sql語言也會相應發生變化,給維護造成一定成本。
2.1笛卡爾積
-- 99 笛卡爾積 select * from dept d cross join emp e
2.2自然連線
NATURAL JOIN子句基於兩個表中列名完全相同的列產生連線
[1]兩個表有相同名字的列
[2]資料型別相同
[3]從兩個表中選出連線列的值相等的所有行
-- [2]自然連線 select * from dept d natural join emp e
注意:自然連線最優的使用場景是:主外來鍵關係且主外來鍵欄位只有一個。
2.3using關鍵字
using 主要用於指定連線欄位。
[1] 按照指定的欄位連線兩個表。
[2] 選指定欄位值相同的資料行。
2.4on關鍵字指定連線條件
自然連線的條件是基於表中所有同名列的等值連線,為了設定任意的連線條件或者指定連線的列,需要使用ON子句連個表的關聯用關鍵字 join ,預設內連線(inner) 語法
select filed1,fild2,… from table1 join table2 on condition1 [join table3 on condition2]*
-- 查詢出員工的部門名稱 select * from dept d join emp e on d.deptno = e.deptno -- 查詢scott的上級領導 select e.ename,m.ename from emp e join emp m on e.mgr = m.empno where e.ename = 'SCO%T'
2.5使用jion on 連線3張表
-- 查詢SCO%T部門名稱和薪資等級 select e.ename,d.dname,sg.grade from dept d join emp e on d.deptno = e.deptno join salgrade sg on e.sal between sg.losal and sg.hisal where e.ename = 'SCO%T' -- 查詢SCO%T的管理者名稱和其管理者的薪資等級 select e.ename,m.ename,sg.grade from emp e join emp m on e.mgr = m.empno join salgrade sg on m.sal between sg.losal and sg.hisal where e.ename = 'SCO%T'
2.6外連線
外連線在99語法中通過outer 關鍵字,按照主從表的位置可以分為left outer/right outer,語法:
select filed1,field2 from table1 left/right outer join table2 on condition1 [left/right outer join table3 on condition2]*
左外連線:
-- 查詢所有部門的所有員工 select * from dept d left outer join emp e on d.deptno = e.deptno
右外連線:
-- 查詢所有部門的所有員工 select * from emp e right outer join dept d on e.deptno = d.deptno;
3.子查詢
sql中查詢是可以巢狀的。一個查詢可以作為另外一個查詢的條件、表。
SELECT select_list FROM table WHERE expr operator (SELECT select_list FROM table);
3.1單行子查詢
當子查詢有單行時,可以取單行中的一個欄位形成單個值用於條件比較。
-- 查詢僱員其薪資在僱員平均薪資以上 -- [1] 查詢員工的平均薪資 select avg(e.sal) "AVGSAL" from emp e --[2] 查詢滿足條件的僱員 select * from emp e where e.sal > (select avg(e.sal) "AVGSAL" from emp e)
3.2多行子查詢
-- 查在僱員中有哪些人是管理者 --【1】查詢管理者 select distinct e.mgr from emp e where e.mgr is not null --【2】查詢指定列表的資訊 in select e.* from emp e where e.empno in (select distinct e.mgr from emp e where e.mgr is not null)
多行子查詢返回的結果可以作為 表 使用,通常結合in、some/any、all、exists。
3.3from後的子查詢
-- 每個部門平均薪水的等級 --【1】部門的平均薪資 select e.deptno,avg(e.sal) "AVGSAL" from emp e group by e.deptno --【2】求等級 select vt0.deptno,vt0.avgsal,sg.grade from (select e.deptno,avg(e.sal) "AVGSAL" from emp e group by e.deptno) VT0,salgrade sg where vt0.avgsal between sg.losal and sg.hisal -- 99 join on select vt0.deptno,vt0.avgsal,sg.grade from (select e.deptno,avg(e.sal) "AVGSAL" from emp e group by e.deptno) VT0 join salgrade sg on vt0.avgsal between sg.losal and sg.hisal
3.4TOP-N
把select得到的資料集提取前n條數。
rownum:表示對查詢的資料集記錄的編號,從1開始。
-- 查詢前10名僱員 select e.*,rownum from emp e where rownum <= 10
rownum和order-by:
--查詢按照薪資降序,前10名僱員
select vt0.*,rownum
from (select e.*
from emp e
order by e.sal desc) VT0
where rownum <= 10
總結
[1] order by 一定在整個結果集出現後才執行。
[2] rownum 在結果集出現後才有編號。
3.5分頁
-- 求查詢6-10號的僱員 select vt0.* from (select e.*,rownum "RN" from emp e where rownum <= 10) VT0 where vt0.rn >= 6
求page=n,pagesize=size的資料
=>[(n-1)*size+1,n*size]
select vt0.* from (select t.*, rownum “RN” from table t where rownum <= n*size) VT0 where vt0.rn >= (n-1)*size+1
3.6行轉列
要想從上表中得到類似下面的結果:
姓名 語文 數學 英語
張三 78 88 98
王五 89 56 89
select ts.name, sum(decode(ts.subject,'語文',ts.score)) "語文", sum(decode(ts.subject,'數學',ts.score)) "數學", sum(decode(ts.subject,'英語',ts.score)) "英語" from test_score ts group by ts.name