多表聯合查詢
通過連接可以建立多表查詢,多表查詢的數據可以來自多個表,但是表之間必須有適當的連接條件。爲了從多張表中查詢,必須識別連接多張表的公共列。一般是在WHERE子句中用比較運算符指明連接的條件。
忘記說明表的連接條件是常見的一種錯誤,這時查詢將會產生表連接的笛卡爾積(即一個表中的每條記錄與另一個表中的每條記錄作連接產生的結果)。一般N個表進行連接,需要至少N-1個連接條件,才能夠正確連接。兩個表連接是最常見的情況,只需要說明一個連接條件。
兩個表的連接有四種連接方式:
* 相等連接。
* 不等連接。
* 外連接。
* 自連接。
1.相等連接
通過兩個表具有相同意義的列,可以建立相等連接條件。使用相等連接進行兩個表的查詢時,只有連接列上在兩個表中都出現且值相等的行纔會出現在查詢結果中。
顯示僱員的名稱和所在的部門的編號和名稱。
執行以下查詢:
1. SELECT emp.ename,emp.deptno,dept.dname FROM emp,dept
- WHERE emp.deptno=dept.deptno;
執行結果如下:
1. ENAME DEPTNO DNAME
- ------------- ------------------------ - ----------
- SMITH 20 RESEARCH
- ALLEN 30 SALES
說明:相等連接語句的格式要求是,在FROM從句中依次列出兩個表的名稱,在表的每個列前需要添加表名,用“.”分隔,表示列屬於不同的表。在WHERE條件中要指明進行相等連接的列。
以上訓練中,不在兩個表中同時出現的列,前面的表名前綴可以省略。所以以上例子可以簡化爲如下的表示:
SELECT ename,emp.deptno,dname FROM emp,dept
WHERE emp.deptno=dept.deptno;
2.外連接
在以上的例子中,相等連接有一個問題:如果某個僱員的部門還沒有填寫,即保留爲空,那麼該僱員在查詢中就不會出現;或者某個部門還沒有僱員,該部門在查詢中也不會出現。
爲了解決這個問題可以用外連,即除了顯示滿足相等連接條件的記錄外,還顯示那些不滿足連接條件的行,不滿足連接條件的行將顯示在最後。外連操作符爲(+),它可以出現在相等連接條件的左側或右側。出現在左側或右側的含義不同,這裏用如下的例子予以說明。
使用外連顯示不滿足相等條件的記錄。
步驟1:顯示僱員的名稱、工資和所在的部門名稱及沒有任何僱員的部門。
執行以下查詢:
1. SELECT ename,sal,dname FROM emp,dept
- WHERE emp.deptno(+)=dept.deptno;
執行結果爲:
1. ENAME SAL DNAME
- ------------------- -------------- ------------------------
3. CLARK 2450 ACCOUNTING
- KING 5000 ACCOUNTING
- MILLER 1300 ACCOUNTING
- ...
- TURNER 1500 SALES
- WARD 1250 SALES
- OPERATIONS
3.不等連接
還可以進行不等的連接。以下是一個訓練實例,其中用到的salgrade表的結構如下:
DESC salgrade
1. 名稱 是否爲空 類型
- ------------------------------------------- ------------------ ------------------
- GRADE NUMBER
- LOSAL NUMBER
- HISAL NUMBER
Grade 表示工資等級,losal和hisal分別表示某等級工資的下限和上限。
表的內容爲:
1. SELECT * FROM salgrade;
1. GRADE LOSAL HISAL
- ------------------- ------------------- -------------
- 1 700 1200
- 2 1201 1400
- 3 1401 2000
- 4 2001 3000
- 5 3001 9999
顯示僱員名稱,工資和所屬工資等級。
執行以下查詢:
1. SELECT e.ename, e.sal, s.grade FROM emp e,salgrade s
- WHERE e.sal BETWEEN s.losal AND s.hisal;
執行結果爲:
1. ENAME SAL GRADE
- ----------------- -------------------- -------------------
3. JONES 2975 4
- BLAKE 2850 4
- CLARK 2450 4
- SCOTT 3000 4
- FORD 3000 4
- KING 5000 5
說明:通過將僱員工資與不同的工資上下限範圍相比較,取得工資的等級,並在查詢結果中顯示出僱員的工資等級。
4.自連接
最後是一個自連接的訓練實例,自連接就是一個表,同本身進行連接。對於自連接可以想像存在兩個相同的表(表和表的副本),可以通過不同的別名區別兩個相同的表。
顯示僱員名稱和僱員的經理名稱。
執行以下查詢:
1. SELECT worker.ename||' 的經理是 '||manager.ename AS 僱員經理
- FROM emp worker, emp manager
- WHERE worker.mgr = manager.empno;
執行結果爲:
1. 僱員經理
2. -------------------------------------------
- SMITH 的經理是 FORD
- ALLEN 的經理是 BLAKE
- WARD 的經理是 BLAKE
說明:爲EMP表分別起了兩個別名worker和manager,可以想像,第一個表是僱員表,第二個表是經理表,因爲經理也是僱員。然後通過worker表的mgr(經理編號)字段同manager表的empno(僱員編號)字段建立連接,這樣就可以顯示僱員的經理名稱了。
注意:經理編號mgr是僱員編號empno之一,所以經理編號可以同僱員編號建立連接。
統計查詢
通常需要對數據進行統計,彙總出數據庫的統計信息。比如,我們可能想了解公司的總人數和總工資額,或各個部門的人數和工資額,這個功能可以由統計查詢完成。
Oracle提供了一些函數來完成統計工作,這些函數稱爲組函數,組函數不同於前面介紹和使用的函數(單行函數)。組函數可以對分組的數據進行求和、求平均值等運算。組函數只能應用於SELECT子句、HAVING子句或ORDER BY子句中。組函數也可以稱爲統計函數。
組函數:
AVG:求平均值
COUNT:求計數值,返回非空行數,*表示返回所有行
MAX:求最大值
MIN:求最小值
SUM:求和
STDDEV:求標準偏差,是根據差的平方根得到的
VARIANCE:求統計方差
分組函數中SUM和AVG只應用於數值型的列,MAX、MIN和COUNT可以應用於字符、數值和日期類型的列。組函數忽略列的空值。
使用GROUP BY 從句可以對數據進行分組。所謂分組,就是按照列的相同內容,將記錄劃分成組,對組可以應用組函數。
如果不使用分組,將對整個表或滿足條件的記錄應用組函數。
在組函數中可使用DISTINCT或ALL關鍵字。ALL表示對所有非NULL值(可重複)進行運算(COUNT除外)。DISTINCT 表示對每一個非NULL值,如果存在重複值,則組函數只運算一次。如果不指明上述關鍵字,默認爲ALL。
求有佣金的僱員人數。
執行以下查詢:
1. SELECT COUNT(comm) FROM emp;
返回結果爲:
1. COUNT(COMM)
- ---------------------
- 4
說明:在本例中,沒有返回全部僱員,只返回佣金非空的僱員,只有4個人。
求僱員表中不同職務的個數。
執行以下查詢:
1. SELECT COUNT( DISTINCT job) FROM emp;
返回結果爲:
1. COUNT(DISTINCT JOB)
- -------------------------------
- 5
說明:該查詢返回僱員表中不同職務的個數。如果不加DISTINCT,則返回的是職務非空的僱員個數。
分組統計
通過下面的訓練,我們來了解分組的用法。
按職務統計工資總和。
步驟1:執行以下查詢:
1. SELECT job,SUM(sal) FROM emp GROUP BY job;
執行結果爲:
- JOB SUM(SAL)
2. ----------------- -------------------
3. ANALYST 6000
4. CLERK 4150
5. MANAGER 8275
6. PRESIDENT 5000
7. SALESMAN 5600
說明:分組查詢允許在查詢列表中包含分組列,對以上實例,因爲是按職務job分組的,所以在查詢列中可以包含job字段,使統計結果很清楚
職務爲ANALYST的僱員的總工資爲6000,職務爲CLERK的僱員的總工資爲4150,依此類推。
注意:在查詢列中,不能使用分組列以外的其他列,否則會產生錯誤信息。
錯誤寫法:SELECT ename,job,SUM(sal) FROM emp GROUP BY job;
多列分組統計
可以按多列進行分組,以下是按兩列進行分組的例子。
按部門和職務分組統計工資總和。
執行以下查詢:
1. SELECT deptno, job, sum(sal) FROM emp
2. GROUP BY deptno, job;
執行結果爲:
DEPTNO JOB SUM(SAL)
------------------ --------- -----------------------
10 CLERK 1300
10 MANAGER 2450
10 PRESIDENT 5000
20 ANALYST 6000
20 CLERK 1900
20 MANAGER 2975
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 5600
說明:該查詢統計每個部門中每種職務的總工資。
分組統計結果限定
對分組查詢的結果進行過濾,要使用HAVING從句。HAVING從句過濾分組後的結果,它只能出現在GROUP BY從句之後,而WHERE從句要出現在GROUP BY從句之前。
統計各部門的最高工資,排除最高工資小於3000的部門。
執行以下查詢:
1. SELECT deptno, max(sal) FROM emp
- GROUP BY deptno
- HAVING max(sal)>=3000;
執行結果爲:
1. DEPTNO MAX(SAL)
- ------------------ ------------------
- 10 5000
- 20 3000
說明:結果中排除了部門30,因部門30的總工資小於3000。
注意:HAVING從句的限定條件中要出現組函數。如果同時使用WHERE條件,則WHERE條件在分組之前執行,HAVING條件在分組後執行。
分組統計結果排序
可以使用ORDER BY從句對統計的結果進行排序,ORDER BY從句要出現在語句的最後。
按職務統計工資總和並排序。
執行以下查詢:
1. SELECT job 職務, SUM(sal) 工資總和 FROM emp
2. GROUP BY job
3. ORDER BY SUM(sal);
執行結果爲:
1. 職務 工資總和
2. ---------------- ------------------
3. CLERK 4150
4. PRESIDENT 5000
5. SALESMAN 5600
6. ANALYST 6000
7. MANAGER 8275
組函數的嵌套使用
在如下訓練中,使用了組函數的嵌套。
求各部門平均工資的最高值。
執行以下查詢:
1. SELECT max(avg(sal)) FROM emp GROUP BY deptno;
執行結果爲:
1. MAX(AVG(SAL))
- -----------------------
- 2916.66667
說明:該查詢先統計各部門的平均工資,然後求得其中的最大值。
注意:雖然在查詢中有分組列,但在查詢字段中不能出現分組列。
子查詢
我們可能會提出這樣的問題,在僱員中誰的工資最高,或者誰的工資比SCOTT高。通過把一個查詢的結果作爲另一個查詢的一部分,可以實現這樣的查詢功能。具體的講:要查詢工資高於SCOTT的僱員的名字和工資,必須通過兩個步驟來完成,第一步查詢僱員SCOTT的工資,第二步查詢工資高於SCOTT的僱員。第一個查詢可以作爲第二個查詢的一部分出現在第二個查詢的條件中,這就是子查詢。出現在其他查詢中的查詢稱爲子查詢,包含其他查詢的查詢稱爲主查詢。
子查詢一般出現在SELECT語句的WHERE子句中,Oracle也支持在FROM或HAVING子句中出現子查詢。子查詢比主查詢先執行,結果作爲主查詢的條件,在書寫上要用圓括號擴起來,並放在比較運算符的右側。子查詢可以嵌套使用,最裏層的查詢最先執行。子查詢可以在SELECT、INSERT、UPDATE、DELETE等語句中使用。
子查詢按照返回數據的類型可以分爲單行子查詢、多行子查詢和多列子查詢。
單行子查詢
查詢比SCOTT工資高的僱員名字和工資。
執行以下查詢:
1. SELECT ename,sal FROM emp
2. WHERE sal>(SELECT sal FROM emp WHERE empno=7788);
執行結果爲:
1. ENAME SAL
2. -------------- --------------------
3. KING 5000
說明:在該子查詢中查詢SCOTT的工資時使用的是他的僱員號,這是因爲僱員號在表中是惟一的,而僱員的姓名有可能相重。SCOTT的僱員號爲7788。
也可以包含兩個或多個子查詢。
1. 在FROM從句中使用子查詢
在FROM從句中也可以使用子查詢,在原理上這與在WHERE條件中使用子查詢類似。有的時候我們可能要求從僱員表中按照僱員出現的位置來檢索僱員,很容易想到的是使用rownum虛列。比如我們要求顯示僱員表中6~9位置上的僱員,可以用以下方法。
查詢僱員表中排在第6~9位置上的僱員。
執行以下查詢:
1. SELECT ename,sal FROM (SELECT rownum as num,ename,sal FROM emp WHERE rownum<=9 )
- WHERE num>=6;
執行結果爲:
1. ENAME SAL
- -------------- --------------------
- BLAKE 2850
- CLARK 2450
- SCOTT 3000
- KING 5000
說明:子查詢出現在FROM從句中,檢索出行號小於等於9的僱員,並生成num編號列。在主查詢中檢索行號大於等於6的僱員。
注意:以下用法不會有查詢結果
SELECT ename,sal FROM emp
WHERE rownum>=6 AND rownum<=9;
集合運算
多個查詢語句的結果可以做集合運算,結果集的字段類型、數量和順序應該一樣。
Oracle共有4個集合操作
UNION:並集,合併兩個操作的結果,去掉重複的部分
UNION ALL:並集,合併兩個操作的結果,保留重複的部分
MINUS:差集,從前面的操作結果中去掉與後面操作結果相同的部分
INTERSECT:交集,取兩個操作結果中相同的部分
使用集合的並運算
查詢部門10和部門20的所有職務。
執行以下查詢:
1. SELECT job FROM emp WHERE deptno=10
- UNION
- SELECT job FROM emp WHERE deptno=20;
執行結果爲:
1. JOB
2. ---------
3. ANALYST
4. CLERK
5. MANAGER
6. PRESIDENT
說明:部門10的職務有PRESIDENT、MANAGER、CLERK;部門20的職務有MANAGER、CLERK、ANALYST。所以兩個部門的所有職務(相同職務只算一個)共有4個:ANALYST、CLERK、MANAGER和PRESIDENT。
將UNION改爲UNION ALL的結果爲:把兩條語句查出來的值全部都顯示,不去掉重複值
使用集合的交運算
查詢部門10和20中是否有相同的職務和工資。
執行以下查詢:
1. SELECT job,sal FROM emp WHERE deptno=10
- INTERSECT
- SELECT job,sal FROM emp WHERE deptno=20;
執行結果爲:
未選定行
說明:部門10的職務有PRESIDENT、MANAGER、CLERK;部門20的職務有MANAGER、CLERK、ANALYST。所以兩個部門的相同職務爲:CLERK和MANAGER。但是職務和工資都相同的僱員沒有,所以沒有結果。
使用集合的差運算
查詢只在部門表中出現,但沒有在僱員表中出現的部門編號。
執行以下查詢:
1. SELECT deptno FROM dept
2. MINUS
3. SELECT deptno FROM emp ;
執行結果爲:
1. DEPTNO
2. ------------------
- 40
說明:部門表中的部門編號有10、20、30和40。僱員表中的部門編號有10、20和30。差集的結果爲40。