Oracle多表查詢與數據更新


2.1 多表查詢

2.1.1 多表查詢的基本語法(重點)

         多表查詢語法如下:

SELECT {DISTINCT} *|查詢列1 別名1,查詢列2 別名2

FROM 表名稱1 別名1,表名稱2 別名2

{WHERE 條件(s)}

{ORDER BY 排序字段 ASC|DESC,排序字段 ASC|DESC}

例:同時查詢emp和dept表

SQL> select * from emp,dept;

發現返回了56條數據,emp一個才14條,dept表才4條。56=14*4。

查詢emp表的記錄數:

SQL> select count(*) from emp;

         說明使用多表查詢的時候會產生笛卡爾積,要想去掉笛卡爾積,必須使用字段進行關聯操作。

在emp和dept表中都有一個deptno字段,屬於關聯字段。

例:加入where語句消除笛卡爾積

Select * from emp,dept

Where emp.deptno=dept.deptno;

例:查詢雇員的編號、姓名、部門編號、部門名稱即部門位置。

select e.deptno,e.ename,e.deptno,d.dname,d.loc

from emp e,dept d

where e.deptno=d.deptno;

例:查詢每個雇員的姓名、工作、雇員的直接上級領導的姓名

select e.ename name,e.job job,m.ename mgr

from emp e,emp m

where e.mgr=m.empno;

例:要求繼續擴展,將部門名稱也列出來。

select e.ename name,e.job job,m.ename mgr,d.dname

from emp e,emp m,dept d

where e.mgr=m.empno and e.deptno=d.deptno;

思考:要求查詢出每個雇員的姓名、工資、部門名稱,工資在公司的等級,及其領導的姓名及工資等級。

select e.ename name, e.sal sal,d.dname dname,s.grade grade,m.ename mgr,ms.grade

from emp e,dept d,salgrade s,emp m,salgrade ms

where (e.deptno=d.deptno )and

 ( e.sal between s.losal and s.hisal) and

 ( e.mgr=m.empno) and

 (m.sal between ms.losal and ms.hisal);

進一步擴展:要求按照以下格式顯示工資等級

l  1:第五等工資

l  2:第四等工資

l  3:第三等工資

l  4:第二等工資

l  5:第一等工資

select e.ename name,e.sal ,d.dname dname,

decode(s.grade,1,'第五等工資',2,'第四等工資',3,'第三等工資',4,'第二等工資' ,5,'第一等工資' ) grade,m.ename mgr,

decode(ms.grade,1,'第五等工資',2,'第四等工資',3,'第三等工資',4,'第二等工資' ,5,'第一等工資' ) mgrade

from emp e,dept d,salgrade s,emp m,salgrade ms

where (e.deptno=d.deptno )and ( e.sal between s.losal and s.hisal) and ( e.mgr=m.empno) and (m.sal between ms.losal and ms.hisal);

 

2.1.2、左、右連接(重點)

Dept表中有4條數據

 

將emp和dept關聯查詢,查詢發現只寫出3個部門,因為雇員表中並沒有40部門的雇員。

select e.ename ,e.deptno,d.dname

from emp e,dept d

where e.deptno(+)=d.deptno;

 

可以發現40部門出現了。這里用到了右連接,具有以下規律:

l  (+)在=左邊表示右連接

l  (+)在=右邊表示左連接

 

select e.ename ,e.deptno,d.dname

from emp e,dept d

where e.deptno=d.deptno(+);

 

發現以上的(+)沒起到作用,無法顯示40部門信息。

左、右連接在一般在開發使用較多,實際上之前的查詢雇員姓名及每個雇員領導的時候就應該用到左、右連接。

 e.mgr = m.empno(+)                        e.mgr = m.empno

select e.empno,e.ename ,m.ename,m.empno

from emp e,emp m

where e.mgr = m.empno(+);

2.1.3 SQL:1999語法對SQL的支持(了解)

SQL:1999語法格式:

SELECT table1.column,table2.column

FROM table1 [CROSS JOIN table2]|

[NATURAL JOIN table2]|

[JOIN table2 USING(column_name)]|

[JOIN table2 ON(table1.column_name=table2.column_name)]|

[LEFT|RIGHT|FULL OUTER JOIN table2 ON(table1.column_name=table2.column_name)];

例:交叉連接(CROSS JOIN):產生笛卡爾積

select * from emp cross join dept;

例:自然連接(NATURAL JOIN):自動進行關聯字段的匹配。

select * from emp natural join dept;

例:USING子句:直接關聯的操作列

select * from emp e join dept d using(deptno) where deptno=30;

例:ON子句,用戶自己編寫的連接條件。

SELECT * FROM emp e JOIN dept d ON(e.deptno=d.deptno) WHERE e.deptno=30 ;

例:左連接(左外連接)、右連接(右外連接):LEFT JOIN,RIGHT JOIN

select e.ename,d.deptno,d.dname,d.loc

from emp e right outer join dept d

on (e.deptno=d.deptno);

2.2 組函數及分組統計(重點)

2.2.1 組函數

在SQL中常用的組函數有以下幾個:

l  COUNT():求出全部的記錄數

l  MAX():求出一組中的最大值

l  MIN():求出最小值

l  AVG():求出平均值

l  SUM():求和

例:

Select count(empno)from emp;

Select min(sal) from emp;

例:求20部門的總工資

Select sum(sal) from emp where deptno=20;

2.2.2 分組統計

分組統計需要用GROUPBY進行分組,SQL語法格式:

SELECT {DISTINCT} * |列1 別名1,列2 別名2

FROM 表1 別名1,表2 別名2

{WHERE 條件(s)}

{GROUP BY  分組條件}

{ORDER BY 排序字段 ASC|DESC , 排序字段ACS | DESC ,…}

例:求出每個部門雇員總數。

select deptno, count(empno) from emp group by (deptno);

注意點:觀察以下代碼

SELECT deptno,COUNT(empno) FROM emp ;

 

         以上代碼不能正確執行,是因為:

1 如果程序中使用了分組函數,則有兩種可以使用的情況:

n  程序中存在了GROUP BY,並指定了分組條件,這樣可以將分組條件一起查詢出來;

n  如果不使用分組的話,則只能單獨的使用分組函數。

2 在使用分組函數的時候,不能出現分組函數和分組條件以外的字段。

SELECT deptno,empno,COUNT(empno)

FROM emp

GROUP BY deptno ;

 

例:按部門分組,並顯示部門的名稱,及每個部門的員工數。

select count(e.empno) ,d.dname

from emp e,dept d

where e.deptno=d.deptno

group by d.dname;

例:求出平均工資大於2000的部門編號和平均工資

select deptno,avg(sal)

from emp

where avg(sal)>2000

group by deptno;

 

分組函數只能在分組中使用,不允許在where語句中出現。如果現在研指定分組發條件。則只能通過第二種條件的指令:HAVING,語法格式:

SELECT {DISTINCT} * 列1 別名1,列2 別名2

FROM 表1 別名1,表2 別名2

{WHERE 條件(s)}

{GROUP BY 分組條件{HAVING分組條件}}

{ORDER BY 排序字段ASC|DESC , 排序字段 ACS | DESC ,…}

例:使用HAVING完成以上操作

select deptno,avg(sal)

from emp

group by deptno HAVING avg(sal) >2000;

例:顯示非銷售人員工作名稱以及從事同一個工作雇員的工資的總和,並且滿足從事同一工作的雇員的月工作合計大於5000,輸出結果按工資的合計升序排列。

select job,sum(sal)

from emp

where job<> 'SALESMAN'

group by job having sum(sal)>5000

order by sum(sal);

分組的簡單原則:

只要一列上存在重復的內容才有可能考慮到分組

注意:

         分組函數可以嵌套使用,但是在嵌套使用的時候不能再出現分組條件的查詢語句。

例:求出平均工資最高的部門工資

錯誤代碼:

select deptno ,max(sum(sal))

from emp

group by deptno;

正確代碼:

select max(sum(sal))

from emp

group by deptno;

2.3 子查詢

         子查詢:在一個查詢內部還包含另外一個查詢,格式:

SELECT {DISTINCT} * | 列1 別名1,列2 別名2

FROM 表1 別名1,表2 別名2

(

SELECT {DISTINCT} * |列1 別名1,列2 別名2

FROM表1 別名1,表2 別名2

{WHERE 條件(s)}

{GROUP BY 分組條件 {HAVING分組條件}}

{ORDER BY 查詢字段ASC|DESC , 查詢字段ACS | DESC , }

) 別名,

{WHERE條件(s)

(

SELECT {DISTINCT} * |列1 別名1,列2 別名2

FROM表1 別名1,表2 別名2

{WHERE條件(s)}

{GROUP BY分組條件{HAVING分組條件}}

{ORDER BY 查詢字段ASC|DESC , 查詢字段ACS | DESC , }

)

}

{GROUP BY {HAVING }}

{ORDER BY ASC|DESC , ACS | DESC , }

例:要求查詢出比7654工資高的全部雇員信息

l  首先要知道7654的工資是多少

select sal s1 from emp where empno=7654;

l  之后要以以上的結果作為后續查詢的依據,只有是其他的工作大於s1,則符合條件。

select * from emp

where sal>(select sal s1 from emp where empno=7654);

所有子查詢必須在()中編寫代碼。

子查詢在操作中又分為以下三類:(面試題)

l  單列子查詢:返回的結果是一列的一個內容,出現幾率高;

l  單行子查詢:返回多個列。有可能是一條完整的記錄

l  多行子查詢:返回多條記錄

例:要求查詢出工資比7654高,同時與7788從事相同工作的全部雇員信息。

select * from emp

where sal>(select sal s1 from emp where empno=7654) and

job=(select job from emp where empno=7788);

思考:

要求查詢出:部門名稱、部門的員工數,部門的平均工資,部門的最低收入雇員的姓名。

1、求出每個部門的員工數、平均工資

select deptno,count(deptno),avg(sal)

from emp

group by deptno;

2、查詢部門的名稱,需關聯dept表

select d.dname,ed.deptno,ed.cnt,ed.arg

from dept d,(

select deptno,count(deptno) cnt,avg(sal) arg

from emp group by deptno) ed

where d.deptno=ed.deptno;

3、求出最低收入的雇員姓名

select d.dname,ed.deptno,ed.cnt,ed.arg,ed.m,e.ename

from dept d,emp e,

(select deptno,count(deptno) cnt,avg(sal) arg,min(sal) m

from emp group by deptno) ed

where d.deptno=ed.deptno and e.sal= ed.m;

         如果此時在一個部門中同時存在兩個工資最低的雇員,則程序就會出錯。在子查詢中存在以下三種查詢的操作符號:

l  IN:指定一個查詢的范圍

l  ANY:

=ANY:與IN的操作符功能完全一樣

>ANY:比里面最小的值要大

<ANY: 比最大的值要小

l  ALL

>ALL:比最大值要大的

<ALL:比最小值要小的

例:求出每個部門的最低工資的雇員信息:IN

有多個部門,因此返回的值肯定的多個,此時可以用IN指定一個操作范圍。

select * from emp

where sal IN (select min(sal) from emp group by deptno);

 

例:ANY操作

l  =ANY: 與IN的操作符功能完全一樣

select * from emp where sal =ANY (select min(sal) from emp group by deptno);

l  >ANY: 比里面最小的值要大(所有工資大於800的),共13條數據

select * from emp where sal >ANY (select min(sal) from emp group by deptno);

l  <ANY: 比最大的值要小(所有工資小於1300的)

select * from emp where sal <ANY (select min(sal) from emp group by deptno);

 

ALL操作

l  >ALL:比最大值要大的(所有工資大於1300的雇員的信息)

l  <ALL:比最小值要小的(所有工資小於800的雇員的信息)

select * from emp where sal >ALL (select min(sal) from emp group by deptno);

    對於子查詢來講,還可以進行多列子查詢,一個子查詢中同時返回多個查詢的列。

select *

from emp

where (sal,NVL(comm,-1)) IN(

select sal,NVL(comm,-1) from emp where deptno=20);

 

2.4 數據庫更新操作

         數據庫的主要操作分為兩種:

l  數據庫的查詢操作:SELECT

l  數據庫的更新操作:INSERT(添加)、UPDATE(修改,更新)、DELETE(刪除)

復制一份emp表的信息:

create table myemp as select * from emp;

2.4.1 添加數據

         添加數據的語法:

INSERT INTO 表名稱[(字段名稱1,字段名稱2,…)]VALUES(值1,值2,…);

例:為myemp表添加一條數據

l  使用標准的做法完成(推薦)

insert into myemp (empno,ename,job,mgr,hiredate,sal,comm,deptno)

 values(7899,'張三','清潔工',7369,'14-2月-1995',500,300,40);

l  使用簡略的寫法(不推薦)。因為要添加所有字段的內容,所有可以不寫上字段名稱,只有值的數量及順序與數據表中的一致即可。

insert into myemp values(8899,'李四','清潔工',7369,'14-2月-1995',510,300,40);

例:要求插入一個新雇員,但是該雇員沒有領導,也沒有獎金。

l  第一種做法:明確寫出要插入的字段

insert into myemp (empno,ename,job,hiredate,sal,deptno) values(3242,'王五','清潔工','13-6月-2000',5400,40);

l  第二種做法:如果插入時沒有明確寫出字段名稱的話,使用null表示不插入的字段的具體內容。

insert into myemp values(3242,'王五','清潔工',null,'13-6月-2000',5400,null,40);

 

         之前插入數據的時候,日期的格式是按照表中固定的格式,如果現在的日期格式的“2014-01-14”的話,那么就要用TO_DATE()函數,將字符串類型變為DATE類型數據。

Insert into myemp values(8888,'趙六','清潔工',null,to_date('2014-01-14','yyyy-mm-dd'),6000,null,40);

2.4.2 修改數據

         在SQL中使用UPDATE語句可以完成數據的修改功能,語法格式:

修改全部:UPDATE 表名稱 SET 要修改的字段 = 新值,要修改的字段 = 新值,…

修改局部:UPDATE 表名稱 SET 要修改的字段 = 新值,要修改的字段 = 新值,…WHERE 修改條件

         從一般的開發角度上講,修改操作一般都是加入修改條件。

例:將myemp表中所有雇員的佣金修改為1000——>修改全部

update myemp set comm=1000;

例:將編號為7899的雇員的工作修改為7000——>指定修改條件

update myemp set sal=7000 where empno=7899;

例:將7369、8899、7788的領導及獎金取消

Update myemp set mgr =null,comm=null where empno in(7369,8899,7788);

2.4.3 刪除數據

         在SQL中使用DELETE命令刪除記錄,語法格式如下:

刪除全部:DELETE FROM 表名稱;

刪除局部:DELETE FROM 表名稱 WHERE 刪除條件;

例:刪除編號為7899的雇員信息

Delete from myemp where empno=7899;

例:刪除表的全部內容

Delete from myemp;

2.5 事務處理

例:建一個只含10部門雇員的臨時表

Create table emp10 as select * from emp where deptno=10;

 

刪除emp10表中7782的雇員后,再查詢發現已經將此雇員信息刪除掉了,但是選擇打開第二個窗口,再次查詢emp10,發現7782還存在。實際上這就是Oracle中事務處理的概念。

事務處理:保證數據操作的完整性,所有的操作要么同時成功,要么同時失敗。

在Oracle中對於每個連接到數據庫的窗口(sqlplus、sqlplusw)連接之后實際上都會與數據庫的連接建立一個session,即:每一個連接到數據庫上的用戶都表示創建了一個session。

一個是session對數據庫所做的修改,不會立刻反應到數據庫的真實數據上,是允許回滾的,當一個session提交所有的操作之后,數據庫才真正的做出修改。

n  提交事務:commit

n  回滾事務:rollback;

|-如果數據已經被提交了,則肯定無法回滾。

在Oracle中關於事務的處理上也會存在一種死鎖的概念。

n  一個session如果更新了數據庫中的記錄,其他session是無法立刻更新的,要等待對方提交之后才允許更新。

2.6 查詢練習

1、列出所有至少有一個員工的部門。

select dn.deptno,d.dname

from dept d,(

select deptno  from emp

group by deptno having count(deptno) > 0) dn

where d.deptno=dn.deptno;

2、列出所有薪水比“SMITH”高的員工。

select * from emp

where sal >(

select sal from emp where ename='SMITH');

3、列出所有員工的姓名及直接上級的姓名

select e.ename name, m.ename mgr

from emp e,emp m

where e.mgr=m.empno;

4、列出所有受雇日期早於直接上級的員工的編號,姓名,部門名稱

select  e.empno,e.ename,e.hiredate,m.hiredate,d.dname

from emp e,emp m,dept d

where e.mgr=m.empno and e.hiredate -m.hiredate<0 and d.deptno=e.deptno;

5、列出部門名稱和這些部門的員工信息,同時列出沒有員工的部門。

select d.dname,d.deptno,e.empno,e.ename

from dept d,emp e

where d.deptno=e.deptno(+);

6、列出所有工作為’CLERK’的姓名及其部門名稱,部門的人數。

select e.ename n,d.dname d,j.c

from emp e,dept d,(select deptno,count(deptno) c

from emp group by deptno) j

where job='CLERK' and d.deptno=e.deptno and j.deptno=e.deptno ;

7、求出最低工資大於1500的各種工作及其從事此工作的全部雇員人數。

select job ,min(sal), count(empno)

from emp

group by job having  min(sal)>1500;

select e.job,count(e.empno)

from emp e

where e.job IN (

select job

from emp

group by job having  min(sal)>1500)

group by e.job;

8、列出在部門’SALES’工作的員工的姓名,假定不知道銷售部門的編號。

select e.ename,e.deptno,d.dname

from emp e,dept d

where e.deptno=d.deptno and d.dname='SALES';

select ename

from emp

where deptno=(select deptno from dept where dname='SALES');

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

select e.deptno,e.ename,e.sal,d.dname,d.loc,m.ename,g.grade

from emp e,dept d,emp m,salgrade g

where e.sal > (select avg(sal) from emp) and e.deptno=d.deptno

and e.mgr=m.empno(+)  and e.sal between g.losal and g.hisal;

10、列出與’SCOTT’從事相同工作的所有員工及其部門名稱。

select e.* ,d.dname

from emp e,dept d

where job=(select job from emp where ename='SCOTT')

and e.deptno=d.deptno and ename<>'SCOTT';

11、列出薪資等於部門30中員工薪資的所有員工的姓名和薪資

select ename,sal,deptno

from emp

where sal IN (

select sal from emp where deptno=30)

and deptno<>30;

12、列出薪資高於部門30工作的所有員工的薪資的員工姓名和薪資、部門

select e.ename,e.sal,e.deptno,d.dname

from emp e,dept d

where sal >ALL (

select sal from emp where deptno=30)

and e.deptno=d.deptno and e.deptno <>30;

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

select d.dname,e.*

from dept d,(select deptno,count(empno) con,avg(sal),

round(avg(months_between(sysdate,hiredate))/12,2) year

from emp group by deptno) e

where d.deptno=e.deptno;

select d.dname,count(e.empno),avg(sal),avg(months_between(sysdate,hiredate)/12) year

from emp e,dept d

where d.deptno=e.deptno

group by d.dname;

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

select d.*,ed.c

from dept d,(select deptno,count(deptno) c

from emp group by deptno) ed

where d.deptno=ed.deptno;

 

但是以上的查詢中沒有包含部門40,因為部門40沒有任何雇員,所有部門40的員工人數應該使用0表示。

select d.*,NVL(ed.c,0)

from dept d,(select deptno,count(deptno) c

from emp group by deptno) ed

where d.deptno=ed.deptno(+);

 

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

select e*

from emp e,(select job ,min(sal) m

from emp group by job) de

where e.sal=de.m and e.job=de.job;

select *

from emp

where sal IN(select min(sal)

from emp group by job) ;

16、列出各個部門MANAGER的最低工資

select deptno,min(sal)

from emp

where job='MANAGER'

group by deptno;

17、列出所有員工的年薪,按年薪從低到高排序

select ename,job,(sal+NVL(comm,0))*12 ysal

from emp

order by ysal asc;

18、求出部門名稱中帶有’S’字符的部門員工的總工資、部門人數

select d.dname,sum(e.sal),count(e.deptno)

from emp e,dept d

where e.deptno = d.deptno and d.dname like'%S%'

group by d.dname;

select deptno,sum(sal),count(empno)

from emp

where deptno IN(select deptno from dept where dname like'%S%')

group by deptno;

19、改任職超過30年的員工加薪10%

update emp set sal=1.1*sal where months_between(sysdate,hiredate)/12 > 30;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM