1. 程式人生 > >Oracle學習筆記<4>

Oracle學習筆記<4>

多表查詢

1.什麼是多表查詢?
一次select語句需要查詢的內容來自於不止一張表。
同時從多張表中查詢資料。

單表查詢:
select id,last_name,salary
from s_emp
where salary > 1400 and dept_id in(41,42)
order by salary desc,id asc;
單表查詢能查到的資料是有限的。

查詢所有員工的id、last_name?
select id,last_name
from s_emp;

查詢所有部門的id、name?
select id,name
from s_dept;

查詢所有員工id、last_name以及所在部門的
id和name?
select id,last_name,id,name
from s_emp,s_dept;

語法:
select ...
from 表1,表2,表3.....
where ...
order by ....;

出現欄位名衝突時,要使用 表名.列名 的形式,
宣告可能出現衝突的欄位來自於哪張表。
select s_emp.id,last_name,s_dept.id,name
from s_emp,s_dept;

還可以給表名起一個別名。
起到的別名可以在整個select語句中代替表名使用。
語法:
select 別名1.欄位,別名2.欄位......
from 表1 別名1,表2 別名2;


查詢所有員工的id、last_name以及
所在部門的id、name?
select s1.id,s1.last_name,s2.id,s2.name
from s_emp s1,s_dept s2;


2.消除笛卡爾積
笛卡爾積是數學運算中集合進行乘法運算所產生的結果集。

A = { 1 , 2 , 3 }
B = { a , b }

計算:A x B = {(1,a),(1,b),(2,a),(2,b)
(3,a),(3,b)}
一共有2x3=6個結果。

資料庫進行多表查詢,就會產生笛卡爾積。

表1:學生姓名錶
學號 姓名
1 張三
2 李四
3 王五
-------------------
表2:學生成績表
學號 分數
1 80
2 90
3 70
要求:查詢所有學生的id、姓名以及成績?

1 張三 1 80
1 張三 2 90
1 張三 3 70

2 李四 1 80
2 李四 2 90
2 李四 3 70

3 王五 1 80
3 王五 2 90
3 王五 3 70

思路:
使用where關鍵字增加、指定查詢條件,
從笛卡爾積中把不需要的資料篩除出去。

1)等值連線
將兩張表中產生關聯的欄位使用等號進行連線。
查詢所有員工的id、last_name以及
所在部門的id、name?
欄位:s_emp.dept_id = s_dept.id

select s1.id,s1.last_name,s2.id,s2.name
from s_emp s1,s_dept s2
where s1.dept_id = s2.id;

2)不等值連線
大於
大於等於
小於
小於等於
邏輯比較符:between in

查詢所有員工id、last_name以及
工資收入等級?
select e.id,e.last_name,g.name
from s_emp e,s_gender g
where e.salary between g.minSal and g.maxSal;

或者:where e.salary >=g.minSal
and e.salary <= g.maxSal;

表1:員工表
id salary
1 900
2 1300
3 2100

表2:工資等級表
最小值 最大值 等級名稱
0 1000 藍領
1000 1500 白領
1500 2500 金領

結果:
員工ID 員工工資 最小值 最大值 等級名稱
1 900 0 1000 藍領
1 900 1000 1500 白領
1 900 1500 2500 金領
2 1300 0 1000 藍領
2 1300 1000 1500 白領
2 1300 1500 2500 金領
3 2100 0 1000 藍領
3 2100 1000 1500 白領
3 2100 1500 2500 金領

3)外連線
a)左外連線
查詢所有員工的id、last_name以及
所在部門的id、name?
select s1.id,s1.last_name,s2.id,s2.name
from s_emp s1,s_dept s2
where s1.dept_id = s2.id;

SQL:insert into s_emp(id,last_name)
values(999,'_briup');

查詢所有員工的id、last_name以及
所在部門的id、name?要求把沒有部門的員工
也顯示出來?
思路:讓員工表 左外連線 到部門表。

左外連線:
A左外連線到B,就可以查出來沒有B的A。

語法:
1)標準SQL
一套規範、標準
拿到任何一款關係型資料庫中執行。
select...
from 表1 left [outer] join 表2
on 連線條件;

select e.id,e.last_name,d.id,d.name
from s_emp e left join s_dept d
on e.dept_id = d.id;
兩張表順序不能顛倒。

2)Oracle特色語法
符號:(+)
原則:把(+)放在資料較少的一方。
語法和多表查詢的語法一致。
select e.id,e.last_name,d.id,d.name
from s_emp e,s_dept d
where e.dept_id = d.id(+);

練習:
查詢所有員工資訊和部門資訊,
要求把沒有員工的部門也顯示出來?
select e.id,e.last_name,d.id,d.name
from s_emp e,s_dept d
where e.dept_id(+)= d.id;


b)右外連線
右外連線和左外連線就是相反的。
A表左外連線到B表,相當於B表右外連線到A表。

語法:
select...
from 表1 right [outer] join 表2
on 連線條件;

左外連線:
select e.id,e.last_name,d.id,d.name
from s_emp e left join s_dept d
on e.dept_id = d.id;
右外連線:
select e.id,e.last_name,d.id,d.name
from s_dept d right join s_emp e
on e.dept_id = d.id;
以上兩種寫法是等價的。

練習:
先向資料庫中插入一條資料:
insert into s_dept(id,name)
values(1000,'Teaching');
commit;

查詢所有員工的id、last_name以及對應部門的
id、name?要求把沒有員工的部門也查詢出來?
使用左外連線和右外連線兩種方式。

c)全連線
等同於同時包含左外連線和右外連線。
相當於A表同時左右外連線到B表,
或A、B兩表互為左/右外連線。

語法:
select ...
from 表1 full join 表2
on 連線條件;

查詢所有員工的資訊和部門資訊?
要求把所有沒有員工的部門
以及沒有部門的員工全部都顯示出來?
select e.id,e.last_name,d.id,d.name
from s_emp e full join s_dept d
on e.dept_id = d.id;

全連線沒有Oracle特色語法,
如果要使用全連線,必須寫標準SQL。

4)自連線
一張表自己和自己產生關聯。
一張表,查詢的時候當成多張表使用。

查詢所有員工的id、last_name以及
對應經理的id、last_name?
要求把沒有經理的員工也顯示出來?
關係:員工的manager_id = 經理的id;
select s1.id,s1.last_name,s2.id,s2.last_name
from s_emp s1,s_emp s2
where s1.manager_id = s2.id(+);

編號 姓名 經理編號
1 張三 7
2 李四 9
....
7 王五 10
9 趙六 10

5)集合連線
查詢前20條資料 - 查詢前10條資料

3.Oracle資料庫中的偽列
偽列不用來儲存資料,所以不是一個真正意義的欄位。
也不存在於任何一張表中。
偽列出現在每一次select查詢語句的結果中。

1)rowid
標識當前資料的物理儲存位置。
select id,last_name,rowid
from s_emp;
2)rownum
標識當前查詢結果中資料的標號。
注意:rownum必須從1開始。
先有查詢結果,再有rownum欄位。
select id,last_name,rownum
from s_emp;

查詢員工表中前十條資料?
select id,last_name
from s_emp
where rownum <= 10;

查詢員工表中第11-20條資料?
select id,last_name
from s_emp
where rownum>=11 and rownum <=20;

select id,last_name,salary
from (select id,last_name,rownum as rn
from s_emp) e
where rn >=11 and rn <=20;