1. 程式人生 > >Oracle復雜查詢及總結

Oracle復雜查詢及總結

bwt 思路 多行 過濾 單獨使用 sys back nvl 沒有

一、復雜查詢

1、 列出至少有一個員工的所有部門編號、名稱,並統計出這些部門的平均工資、最低工資、最高工資。

1、確定所需要的數據表:

  • emp表:可以查詢出員工的數量;
  • dept表:部門名稱;
  • emp表:統計信息;

2、確定已知的關聯字段:

  • emp.deptno=dept.deptno;  

第一步:找出至少有一個員工的部門編號

SELECT deptno,COUNT(empno)
FROM emp
GROUP BY deptno
HAVING COUNT(empno)>1;

第二步:找到部門名稱,肯定使用部門表,因為現在的數據量較小,所以可以將之前的emp表和dept表兩個進行連接,統一采用多字段分組的方式查詢;

SELECT d.deptno,d.dname,COUNT(e.empno)
FROM emp e,dept d
WHERE e.deptno=d.deptno(+)
GROUP BY d.deptno,d.dname
HAVING COUNT(e.empno)>1;

第三步:依然需要繼續統計

SELECT d.deptno,d.dname,COUNT(e.empno),AVG(sal),MIN(sal),MAX(sal)
FROM emp e,dept d
WHERE e.deptno=d.deptno(+)
GROUP BY d.deptno,d.dname
HAVING COUNT(e.empno)>1;

2、 列出薪金比“SMITH”或“ALLEN”多的所有員工的編號、姓名、部門名稱、其領導姓名。

1、確定所需要的數據表:

  • emp表:查詢出“SMITH”或“ALLEN”工資;
  • emp表:最終的顯示需要編號、姓名;
  • emp表:領導的姓名,自身關聯;
  • dept表:部門名稱;

2、確定已知的關聯字段:

  • 雇員和領導:emp.mgr=memp.empno;
  • 雇員和部門:emp.deptno=dept.deptno;

第一步:找出“SMITH”或“ALLEN”的工資

SELECT sal FROM emp WHERE ename IN(‘SMITH‘,‘ALLEN‘);

第二步:以上的查詢返回的多行單列的記錄,按照子查詢的要求在WHERE子句中寫合適,所以這個時候將上面的查詢作為一個子查詢出現,繼續查詢符合此要求的員工的編號、姓名。

SELECT e.empno,e.ename
FROM emp e
WHERE e.sal>ALL(
    SELECT sal
    FROM emp
    WHERE ename IN(‘SMITH‘,‘ALLEN‘));

第三步:查詢出部門的名稱,引入部門表,同時增加消除笛卡爾積的條件

SELECT e.empno,e.ename,d.dname
FROM emp e,dept d
WHERE e.sal>ALL(
    SELECT sal
    FROM emp
    WHERE ename IN(‘SMITH‘,‘ALLEN‘))
    AND e.deptno=d.deptno;

第四步:領導的信息需要emp表自身關聯

SELECT e.empno,e.ename,d.dname,m.ename
FROM emp e,dept d,emp m
WHERE e.sal>ALL(
    SELECT sal
    FROM emp
    WHERE ename IN(‘SMITH‘,‘ALLEN‘))
    AND e.deptno=d.deptno
    AND e.mgr=m.empno(+);

3、 列出所有員工的編號、姓名及其直接上級的編號、姓名,顯示的結果按領導年工資的降序排列。

1、確定所需要的數據表:

  • emp表:員工的編號、姓名;
  • emp表:領導的編號、姓名、計算年薪;

2、確定已知的關聯字段:emp.mgr=memp.empno;

SELECT e.empno,e.ename,m.empno,m.ename,(m.sal+NVL(m.comm,0))*12 income
FROM emp e,emp m
WHERE e.mgr=m.empno(+)
ORDER BY income DESC;

4、列出受雇日期早於其直接上級的所有員工的編號、姓名、部門名稱、部門位置、部門人數。

1、確定所需要的數據表:

  • emp表:雇員的編號、姓名;
  • emp表:求出領導的工作日期;
  • dept表:部門名稱、位置;
  • emp表:統計部門人數;

2、確定已知的關聯字段:

  • 雇員和部門:emp.deptno=dept.deptno;
  • 雇員和領導:emp.mgr=memp.empno;

第一步:列出受雇日期早於其直接上級的所有員工的編號、姓名 —— 自身關聯emp表。

SELECT e.empno,e.ename
FROM emp e,emp m
WHERE e.mgr=m.empno(+) AND e.hiredate<m.hiredate;

第二步:加入部門信息,繼續引入部門表

SELECT e.empno,e.ename,d.dname,d.loc
FROM emp e,emp m,dept d
WHERE e.mgr=m.empno(+) AND e.hiredate<m.hiredate
AND e.deptno=d.deptno;

額外提問,此時的笛卡爾積:emp表的14條 * emp表的14條 * dept表的4條;

第三步:統計部門人數,此時由於要使用統計函數,而且以上的查詢也無法再直接出現統計函數,所以使用子查詢完成

SELECT e.empno,e.ename,d.dname,d.loc,temp.count
FROM emp e,emp m,dept d,(
    SELECT deptno dno,COUNT(empno) count
    FROM emp
    GROUP BY deptno) temp
WHERE e.mgr=m.empno(+) AND e.hiredate<m.hiredate
    AND e.deptno=d.deptno
    AND e.deptno=temp.dno;

當查詢顯示的時候需要統計信息,但是又不能直接使用統計函數查詢的話,通過子查詢在FROM子句之後進行統計。

5、列出部門名稱和這些部門的員工信息(數量、平均工資),同時列出那些沒有員工的部門。

1、確定所需要的數據表:

  • dept表:部門的信息;
  • emp表:求出所有的統計信息;

2、確定已知的關聯字段:emp.deptno=dept.deptno;

SELECT d.deptno,d.dname,d.loc,COUNT(e.empno),AVG(e.sal)
FROM emp e,dept d
WHERE e.deptno(+)=d.deptno
GROUP BY d.deptno,d.dname,d.loc;

6、列出所有“CLERK”(辦事員)的姓名及其部門名稱,部門的人數,工資等級。

1、確定所需要的數據表:

  • emp表:找到辦事員的姓名;
  • dept表:部門名稱;
  • emp表:統計求出部門的人數;
  • salgrade表:查詢工資等級;

2、確定已知的關聯字段:

  • emp表和dept表:emp.deptno=dept.deptno;
  • emp表和salgrade表:emp.sal BETWEEN salgrade.losal AND salgrade.hisal;

第一步:找到所有辦事員的姓名

SELECT e.ename
FROM emp e
WHERE job=‘CLERK‘;

第二步:找到部門信息,引入dept表,同時增加消除笛卡爾積的條件

SELECT e.ename,d.dname
FROM emp e,dept d
WHERE job=‘CLERK‘ AND e.deptno=d.deptno;

第三步:部門人數需要額外的統計,但是本程序的查詢裏面已經不可能繼續使用COUNT()函數,所以寫子查詢統計

SELECT e.ename,d.dname,temp.count
FROM emp e,dept d,(
    SELECT deptno dno,COUNT(empno) count
    FROM emp
    GROUP BY deptno) temp
WHERE e.job=‘CLERK‘ AND e.deptno=d.deptno
    AND d.deptno=temp.dno;

第四步:雇員的工資等級,繼續引入salgrade表

SELECT e.ename,d.dname,temp.count,s.grade
FROM emp e,dept d,(
    SELECT deptno dno,COUNT(empno) count
    FROM emp
    GROUP BY deptno) temp,salgrade s
WHERE e.job=‘CLERK‘ AND e.deptno=d.deptno
    AND d.deptno=temp.dno
    AND e.sal BETWEEN s.losal AND s.hisal;

7、列出最低薪金大於1500的各種工作及從事此工作的全部雇員人數及所在部門名稱、位置、平均工資。

1、確定所需要的數據表:

  • emp表:最低薪金大於1500的工作肯定需要使用emp表統計求出,以及可以求出雇員人數;
  • dept表:求出些雇員所在的部門信息;
  • emp表:統計求出部門的平均工資;

2、確定已知的關聯字段:emp.deptno=dept.deptno;

第一步:使用emp表按照job分組,統計最低工資(HAVING)和人數

SELECT e.job,COUNT(e.empno)
FROM emp e
GROUP BY e.job
HAVING MIN(e.sal)>1500;

第二步:要查詢出雇員所在的部門信息,但是以上的查詢能跟dept表有關聯嗎?

以上的查詢和dept表之間並沒有關聯字段,那麽如果沒有關聯字段,一定會有笛卡爾積產生,但是多表查詢必須要消除笛卡爾積,所以必須聯系;

  • 以上的查詢可以和emp表的job字段關聯;
  • 要引入的dept表也可以和emp表的deptno字段關聯;
SELECT temp.job,temp.count,d.dname,e.ename
FROM dept d,(
    SELECT e.job job,COUNT(e.empno) count
    FROM emp e
    GROUP BY e.job
    HAVING MIN(e.sal)>1500) temp,
    emp e
WHERE e.deptno=d.deptno AND e.job=temp.job;

第三步:求出一個部門的平均工資,使用emp表在子查詢中統計

SELECT temp.job,temp.count,d.dname,e.ename,res.avg
FROM dept d,(
    SELECT e.job job,COUNT(e.empno) count
    FROM emp e
    GROUP BY e.job
    HAVING MIN(e.sal)>1500) temp,
    emp e,(
    SELECT deptno dno,AVG(sal) avg
    FROM emp
    GROUP BY deptno) res
WHERE e.deptno=d.deptno AND e.job=temp.job
    AND e.deptno=res.dno;

本題目之所以出的如此之復雜,目的是訓練大家尋找關聯字段的能力,但是本題目沒有任何的意義,知道就行了。

8、列出在部門“SALES”(銷售部)工作的員工姓名、基本工資、雇傭日期、部門名稱、假定不知道銷售部的部門編號。

1、確定所需要的數據表:

  • emp表:員工姓名、基本工資、雇傭日期;
  • dept表:找到銷售部的部門編號、部門名稱;

2、確定已知的關聯字段:emp.deptno=dept.deptno;

SELECT e.ename,e.sal,e.hiredate,d.dname
FROM emp e,dept d
WHERE e.deptno=d.deptno
AND d.dname=‘SALES‘;

9、列出薪金高於公司平均薪金的所有員工,所在部門,上級領導,公司的工資等級。

1、確定所需要的數據表:

  • emp表:可以求出公司的平均薪金;
  • emp表:員工的信息;
  • dept表:部門的信息;
  • emp表:領導的信息;
  • salgrade表:工資等級;

2、確定已知的關聯字段:

  • 雇員和部門:emp.deptno=dept.deptno;
  • 雇員和領導:emp.mgr=memp.empno;
  • 雇員和工資等級:emp.sal BETWEEN salgrade.losal AND salgrade.hisal;

第一步:求出公司的平均薪金

SELECT AVG(sal) FROM emp;

第二步:將以上的子查詢放在WHERE子句之中,作為一個查詢條件,求出滿足此條件的雇員信息。

SELECT e.empno,e.ename,e.job,e.sal
FROM emp e
WHERE e.sal>(
    SELECT AVG(sal) FROM emp);

第三步:找到部門的名稱

SELECT e.empno,e.ename,e.job,e.sal,d.dname,d.loc
FROM emp e,dept d
WHERE e.sal>(
    SELECT AVG(sal) FROM emp)
    AND e.deptno=d.deptno;

第四步:找到領導的信息

SELECT e.empno,e.ename,e.job,e.sal,d.dname,d.loc,m.ename
FROM emp e,dept d,emp m
WHERE e.sal>(
    SELECT AVG(sal) FROM emp)
    AND e.deptno=d.deptno
    AND e.mgr=m.empno(+);

第五步:找到工資等級

SELECT e.empno,e.ename,e.job,e.sal,d.dname,d.loc,m.ename,s.grade
FROM emp e,dept d,emp m,salgrade s
WHERE e.sal>(
    SELECT AVG(sal) FROM emp)
    AND e.deptno=d.deptno
    AND e.mgr=m.empno(+)
    AND e.sal BETWEEN s.losal AND s.hisal;

10、列出與“SCOTT”從事相同工作的所有員工及部門名稱,部門人數。

1、確定所需要的數據表:

  • emp表:找到SCOTT的工作;
  • emp表:員工的信息;
  • dept表:部門名稱;
  • emp表:部門人數;

2、確定已知的關聯字段:emp.deptno=dept.deptno;

第一步:找到SCOTT的工作

SELECT job FROM emp WHERE ename=‘SCOTT‘;

第二步:以上的子查詢返回單行單列的數據,所以可以在WHERE子句中出現,以這個條件查找滿足要求的雇員信息

SELECT e.empno,e.ename,e.job
FROM emp e
WHERE e.job=(
    SELECT job
    FROM emp
    WHERE ename=‘SCOTT‘)
    AND e.ename<>‘SCOTT‘;

第三步:找到部門名稱

SELECT e.empno,e.ename,e.job,d.dname
FROM emp e,dept d
WHERE e.job=(
    SELECT job
    FROM emp
    WHERE ename=‘SCOTT‘)
    AND e.ename<>‘SCOTT‘
    AND e.deptno=d.deptno;

第四步:找到部門人數,需要統計,所以在FROM子句之中編寫

SELECT e.empno,e.ename,e.job,d.dname,temp.count
FROM emp e,dept d,(
    SELECT deptno dno,COUNT(empno) count
    FROM emp
    GROUP BY deptno) temp
WHERE e.job=(
    SELECT job
    FROM emp
    WHERE ename=‘SCOTT‘)
    AND e.ename<>‘SCOTT‘
    AND e.deptno=d.deptno
    AND temp.dno=e.deptno;

11、列出公司各個工資等級雇員的數量、平均工資。

1、確定所需要的數據表:

  • emp表:統計出數據;
  • salgrade表:得出工資等級;

2、確定已知的關聯字段:emp.sal BETWEEN salgrade.losal AND s.hisal;

本程序實際上就是一個多字段分組而已,唯一不同的是,將分組條件設置為salgrade表中的字段;

SELECT s.grade,s.losal,s.hisal,COUNT(e.empno),AVG(e.sal)
FROM emp e,salgrade s
WHERE e.sal BETWEEN s.losal AND s.hisal
GROUP BY s.grade,s.losal,s.hisal;

12、列出薪金高於在部門30工作的所有員工的薪金的員工姓名和薪金、部門名稱。

1、確定所需要的數據表:

  • emp表:找出所有在30部門工作的雇員的工資;
  • emp表:最終顯示的雇員姓名;
  • dept表:找到部門名稱;

2、確定已知的關聯字段:emp.deptno=dept.deptno;

第一步:找到30部門工作的雇員的工資

SELECT sal FROM emp WHERE deptno=30;

第二步:高於30部門,使用ALL操作符,引入emp表,查詢姓名和薪金

SELECT e.empno,e.ename
FROM emp e
WHERE sal>ALL(
    SELECT sal FROM emp WHERE deptno=30)
    AND e.deptno=d.deptno;

13、列出在每個部門工作的員工數量、平均工資和平均服務期限。

1、確定所需要的數據表:

  • dept表:找到部門信息;
  • emp表:統計出數量、平均工資、平均服務年限;

2、確定已知的關聯字段:emp.deptno=dept.deptno;

直接將dept和emp表關聯,使用多字段分組即可,但是對於服務年限需要一個計算過程。

SELECT d.deptno,d.dname,d.loc,COUNT(e.empno),AVG(e.sal),AVG(MONTHS_BWTWEEN(SYSDATE,e.hiredate)/12) year
FROM emp e,dept d
WHERE e.deptno(+)=d.deptno
GROUP BY d.deptno,d.dname,d.loc;

14、列出所有員工的姓名、部門名稱和工資。

1、確定所需要的數據表:

  • emp表:找到員工姓名;
  • dept表:部門名稱;

2、確定已知的關聯字段:emp.deptno=dept.deptno;

SELECT e.ename,d.dname,e.sal
FROM emp e,dept d
WHERE e.deptno=d.deptno;

15、列出所有部門的詳細信息和部門人數。

1、確定所需要的數據表:

  • emp表:統計信息;
  • dept表:查詢部門信息;

2、確定已知的關聯字段:emp.deptno=dept.deptno;

SELECT d.deptno,d.dname,d.loc,COUNT(e.empno)
FROM emp e,dept d
WHERE e.deptno(+)=d.deptno
GROUP BY d.deptno,d.dname,d.loc;

16、列出各種工作的最低工資及從事此工作的雇員姓名。

1、確定所需要的數據表:

  • emp表:統計出各個工作的最低工資;
  • emp表:查找出雇員姓名;

第一步:按照職位統計各個職位的最低工資

SELECT job,MIN(sal) FROM emp
GROUP BY job;

第二步:將以上的查詢和emp表關聯

SELECT e.ename,e.job,e.sal
FROM emp e,(
    SELECT job,MIN(sal) FROM emp
    GROUP BY job) temp
WHERE e.job=temp.job AND e.sal=temp.min;

17、列出各個部門的MANAGER(經理)的最低薪金、姓名、部門名稱、部門人數。

1、確定所需要的數據表:

  • emp表:找到經理的薪金、姓名;
  • dept表:部門名稱;
  • emp表:統計部門人數;

2、確定已知的關聯字段:emp.deptno=dept.deptno;

第一步:找到所有部門的經理

SELECT deptno,MIN(sal)
FROM emp
WHERE job=‘MANAGER‘
GROUP BY deptno;

第二步:找到姓名,但是以上的子查詢,不能再出現其他的字段

SELECT e.ename,e.sal
FROM emp e,(
    SELECT deptno dno,MIN(sal) sal
    FROM emp
    WHERE job=’MANAGER’
    GROUP BY deptno) temp
WHERE e.deptno=temp.dno AND e.sal=temp.sal AND e.job=‘MANAGER‘;

第三步:加入部門的名稱信息

SELECT e.ename,e.sal,d.dname
FROM emp e,(
    SELECT deptno dno,MIN(sal) sal
    FROM emp
    WHERE job=‘MANAGER‘
    GROUP BY deptno) temp,dept d
WHERE e.deptno=temp.dno AND e.sal=temp.sal AND e.job=‘MANAGER‘
    AND e.deptno=d.deptno;

第四步:統計部門人數

SELECT e.ename,e.sal,d.dname,res.count
FROM emp e,(
    SELECT deptno dno,MIN(sal) sal
    FROM emp
    WHERE job=’MANAGER’
    GROUP BY deptno) temp,dept d,(
    SELECT deptno dno,COUNT(empno) count
    FROM emp
    GROUP BY deptno) res
WHERE e.deptno=temp.dno AND e.sal=temp.sal AND e.job=‘MANAGER‘
    AND e.deptno=d.deptno AND res.dno=d.deptno;

18、列出所有員工的年工資,所在部門名稱,按年薪從低到高排序。

1、確定所需要的數據表:

  • emp表:統計年工資;
  • dept表:部門名稱;

2、確定已知的關聯字段:emp.deptno=dept.deptno;

SELECT e.ename,e.sal*12 income,d.dname
FROM emp e,dept d
WHERE e.deptno=d.deptno
ORDER BY income;

19、查出某個員工的上級主管及所在部門名稱,並要求出這些主管中的薪水超過3000。

1、確定所需要的數據表:

  • emp表:員工的信息;
  • emp表:領導的信息;
  • dept表:部門名稱;

2、確定已知的關聯字段:

  • 雇員和部門:emp.deptno=dept.deptno;
  • 雇員和領導:emp.mgr=memp.empno;
SELECT DISTINCT m.ename,d.dname,m.sal
FROM emp e,emp m,dept d
WHERE e.mgr=m.empno AND m.deptno=d.deptno AND m.sal>3000;

20、求出部門名稱中,帶‘S’字符的部門員工的工資合計、部門人數。

1、確定所需要的數據表:

  • emp表:進行統計信息;
  • dept表:部門名稱;

2、確定已知的關聯字段:emp.deptno=dept.deptno;

SELECT d.dname,SUM(e.sal),COUNT(e.empno)
FROM emp e,dept d
WHERE e.deptno(+)=d.deptno AND d.dname LIKE ‘%S%’
GROUP BY d.dname;

21、給任職日期超過30年或者在87年雇傭的雇員加薪,加薪原則:10部門增長10%,20部門增長20%,30部門增長30%,依次類推。

UPDATE emp SET
    sal=(1 + deptno/100)*sal
WHERE MONTHS_BETWEEN(SYSDATE,hiredate)/12>30
    OR TO_CHAR(hiredate,’yyyy’)=1987;

以上的所有題目作為DML操作的總結,這些題目結果都不重要,關鍵是解決問題的思路,這些只能通過代碼的不斷練習。

二、總結

1、 多表查詢:在進行查詢語句編寫的時候,一定要確定所需要關聯的數據表,而且只要是表的關聯查詢,就一定會存在笛卡爾積的問題,使用關聯字段消除此問題。

在使用多表查詢的時候要考慮到左右連接的問題,Oracle之外的數據庫可以使用SQL:1999語法控制左右連接;

2、 所有的統計函數是用於進行數據統計操作的,而統計要在分組中進行(或者是單獨使用),分組使用GROUP BY子句,是在某一列上存在重復數據的時候才會使用分組操作,而分組後的過濾使用HAVING子句完成,所有的分組函數可以嵌套,但是嵌套之後的分組函數之中不能再有其他的查詢字段,包括分組字段;

3、 子查詢:結合限定查詢、多表查詢、分組統計查詢完成各個復雜查詢的操作,子查詢一般在WHERE和FROM之後出現較多;

4、 數據庫的更新操作一定要受到事務的控制,事務的兩個命令:COMMIT、ROLLBACK,每一個連接到數據庫上的用戶都使用一個SESSION表示;

5、 數據表的分頁查詢顯示依靠ROWNUM偽列,以後在開發之中必定100%要使用。

Oracle復雜查詢及總結