天天看點

Oracle資料庫之第二篇

版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協定,轉載請附上原文出處連結和本聲明。

本文連結:https://blog.csdn.net/zhao1299002788/article/details/101757909

/*
   多表查詢  多個資料庫表做連接配接查詢
     使用場景: 查詢的資料來源為多個表
	*/
	--查詢員工資訊和員工的部門資訊
	select * from emp;
	select * from dept;
	--使用關聯條件 過濾無效資料
	select * from emp,dept where emp.deptno=dept.deptno
	/*
	   内連接配接 隐式内連接配接  select * from A,B where A.列=B.列
			  顯式内連接配接  select * from A inner join B on A.列=B.列
	   特點 做關聯查詢的兩個表 必須雙方條件資料完全比對 才會提取
	*/
	--使用顯式内連接配接實作
	select * from emp inner join dept on emp.deptno = dept.deptno

	/*
	  外連接配接   
		   左外連接配接   select * from A left join B on A.列=B.列
					  
					  以左表為基準 左表資料全部顯示 右表資料作為補充顯示
					  如果沒有資料 顯示空
		   
		   右外連接配接   select * from B right join A on A.列=B.列
					  
					  以右表為基準 右表資料全部顯示 左表資料作為補充顯示
					  如果沒有資料 顯示空
	**/
	--查詢部門資訊和部門下的員工資訊 沒有員工的部門也要顯示
	--左外連接配接實作
	select * from dept left join emp on dept.deptno = emp.deptno
	--右外連接配接實作
	select * from emp right join dept on dept.deptno = emp.deptno
	--特定要求部門顯示左邊
	select dept.*,emp.* from emp right join dept on dept.deptno = emp.deptno
	/*
	 oracle資料庫特有的外連接配接
		文法:使用符号(+) 實作外連接配接
			使用方法:根據需求 将符号放在 作為補充顯示的表的列後面
			select * from A,B where A.列=B.列(+)
	*/
	--使用oracle資料庫特有外連接配接   跟等号左右無關
	select * from emp,dept where emp.deptno(+)=dept.deptno
	select * from emp,dept where dept.deptno=emp.deptno(+)
	/*
	  自連接配接 自己跟自己做關聯查詢
		 自連接配接查詢 别名必須加
		 select * from A A1,A A2 where A1.列=A2.列
		 使用場景:
			 關聯的記錄在同一個表内
	*/
	--查詢員工的資訊和員工的上司資訊
	select e.empno,e.ename,
		   m.empno mgr_no,m.ename  mgr_name
		from emp e,emp m where e.mgr = m.empno
	--在上面基礎上 再查詢員工的部門資訊 dept
	select * from dept
	select e.empno,e.ename,d.dname,
		   m.empno mgr_no,m.ename  mgr_name
		from emp e,emp m,dept d
		where e.mgr = m.empno and d.deptno = e.deptno
	--在上面基礎之上 再查詢員工的工資等級  salgrade
	select * from salgrade

	select e.empno,
		   e.ename,
		   d.dname,
		   s1.grade,
		   m.empno  mgr_no,
		   m.ename  mgr_name
	 from emp e, emp m, dept d, salgrade s1
	 
	 where e.mgr = m.empno
	   and d.deptno = e.deptno
	   and e.sal between s1.losal and s1.hisal
	--在基礎之上查詢上司的工資等級
	select e.empno,
		   e.ename,
		   d.dname,
		   s1.grade,
		   m.empno  mgr_no,
		   m.ename  mgr_name,
		   s2.grade mgr_grade
	 from emp e, emp m, dept d, salgrade s1,salgrade s2
	 where e.mgr = m.empno
	   and d.deptno = e.deptno
	   and e.sal between s1.losal and s1.hisal
	   and m.sal between s2.losal and s2.hisal
	--根據查詢的資料 一張表一張表加的時候 分析表之間的關聯關系
	--oracle的decode函數
	select e.empno,
		   e.ename,
		   d.dname,
		   decode(s1.grade,1,'一級',2,'二級',3,'三級',4,'四級','五級') emp_grade,
		   m.empno  mgr_no,
		   m.ename  mgr_name,
		   s2.grade mgr_grade
	 from emp e, emp m, dept d, salgrade s1,salgrade s2
	 where e.mgr = m.empno
	   and d.deptno = e.deptno
	   and e.sal between s1.losal and s1.hisal
	   and m.sal between s2.losal and s2.hisal



	---錯誤示例
	select e.empno,
		   e.ename,
		   d.dname,
		   s1.grade,
		   m.empno  mgr_no,
		   m.ename  mgr_name,
		   s1.grade mgr_grade
	 from emp e, emp m, dept d, salgrade s1
	 where e.mgr = m.empno
	   and d.deptno = e.deptno
	   and e.sal between s1.losal and s1.hisal
	   and m.sal between s1.losal and s1.hisal

	/*
	  子查詢 在查詢語句中嵌套查詢語句
		   
			文法: 
				  單行子查詢 select * from A where A.列= sql傳回的唯一值
				  多行子查詢 select * from A where A.列 in  sql傳回單列多個值
							 select * from A,(sql語句傳回多行多列臨時表) t 
										where A.列 = t.列
	*/
	--查詢比雇員7654工資高,同時從事和7788相同工作的員工資訊?
	--1.查詢資料  員工資訊
	--2.資料來源  emp表
	--3.查詢條件  工資>7654的工資  工作=7788的工作
	select sal from emp where empno=7654  --1250
	select job from emp where empno=7788  --ANALYST
	--使用結果查詢員工
	select * from emp where sal > 1250 and job = 'ANALYST'
	--使用sql語句替換查詢條件
	select * from emp where 
		 sal > (select sal from emp where empno=7654)
		 and job = (select job from emp where empno=7788)
	--查詢每個部門的最低工資,和最低工資的雇員 及他的部門名稱
	--1.查詢資料 員工資訊  最低工資  部門名稱
	select deptno,min(sal) d_min from emp group by deptno
	--2.資料來源  emp   sql語句得到的臨時表          dept
	--3.查詢條件  員工工資=部門最低工資  本部門
	select e.empno,e.ename,e.sal,d_m.d_min ,dept.dname
		   from emp e,
		   (select deptno,min(sal) d_min from emp group by deptno) d_m,
		   dept 
		   where e.deptno = d_m.deptno and e.sal = d_m.d_min
			and e.deptno = dept.deptno
	--查詢每個部門最低工資的員工資訊
	select * from emp where sal = 
		(select min(sal) d_min from emp group by deptno)   
	select * from emp where sal = (800,950,1300) 

	select * from emp where sal in
		(select min(sal) d_min from emp group by deptno)  
		
	--查詢不是上司的員工資訊
	--1.員工資訊
	--2.emp
	--3.不是上司
	--子查詢空值問題 空值判斷 用is null is not null  其餘判斷結果為UNKNOW
	select * from emp where empno not in( select mgr from emp )
	--需要處理空值 
	select * from emp where empno not in( select mgr from emp where mgr is not null )
	select * from emp where empno not in( select nvl(mgr,0) from emp  )
	select * from emp where empno not in( select mgr from emp where mgr >0 )
	/*
	  子查詢特殊使用
		exists 存在 表達式 (sql語句)
			判斷結果集是否存在 如果存在 exists表達式傳回true
								  不存在 傳回false
	*/
	--簡單示例
	select * from emp where exists(select * from dept)--所有員工資訊
	select * from emp where exists(select * from dept where deptno=123)-- 沒有記錄
	--查詢有員工的部門資訊
	--1.部門資訊
	--2.dept
	--3.部門有員工
	select deptno from emp;  ---得到了有員工的部門編号
	--使用in的方式實作
	select * from dept where deptno in (select deptno from emp) 
	/*
	  普通子查詢 執行順序是 先執行子查詢得到結果用于主查詢
	  exists表達式執行順序更改
	*/
	select * from dept where 
		  exists(select * from emp where emp.deptno = dept.deptno)

	/*
	 
	  mySql 使用limit 提取特定記錄條數
	  oracle 使用 rownum 實作提取記錄  用于分頁使用
		  rownum 是oracle資料庫查詢到記錄 生成的一系列的數值 (1,2,3,4)
	  rownum用于做大于判斷 沒有結果 必須使用子查詢先生成rownum
	  rowun用于小于判斷可以直接查詢出結果
	  
	  rowunm的執行原理 :
		1: 執行sql語句;
		2: 取到第一條記錄,指派rownum為1;
		3: 判斷rownum是否滿足條件,如果不滿足放棄該行,滿足傳回該行.(不滿足條件,rownum還是從1開始進行判斷)
		4: 繼續提取記錄,繼續生成rownum;
		5: 循環步驟3;
	  
	*/
	--rownum的示例
	select rownum,emp.* from emp where  rownum >5   --沒有任何記錄
	select rownum,emp.* from emp where  rownum <5  --前四條記錄
	select rownum,emp.* from emp where  rownum =1 --隻有一條
	select rownum,emp.* from emp where  rownum >1 --沒有
	select rownum,emp.* from emp where  rownum >=1  --所有記錄 
	--先生成rownum 再使用rownum過濾5條記錄以後
	select * from (select rownum r,emp.* from emp) where r>5

	--查詢員工表中 工資最高的前三名
	--工資按照倒序排序 
	select * from emp order by sal desc 
	--加入rownum
	select rownum,emp.* from emp order by sal desc 
	--先按照工資排序 再排序基礎之上生成rownum
	select rownum,t.* from (select * from emp order by sal desc)t
	--判斷rownum提取前三條
	select rownum,t.* from (select * from emp order by sal desc)t where rownum<4
	--提取6--10條記錄
	select * from (
			 select rownum r,t.* from (select * from emp order by sal desc)t) tt
			 where r> 5 and r <11
		  

	--查詢員工表中工資大于本部門平均工資的員工資訊
	--1.員工資訊
	select deptno,avg(sal) d_a from emp group by deptno
	--2.emp
	--3.工資>部門平均工資  必須本部門
	
	行列轉換
	Total		1980		1981		1982		1987
	14			1			10			1			2
		
	
	1: 嘗試豎起一列
		上面是用年的數值做的别名,下面是年對應的入職員工數
		if年1987顯示值是2
			decode(hire_year,'1987',hire_count)
		
	2: 使用聚合函數處理空值	
		
	select *
	  from emp e, (select deptno, avg(sal) d_a from emp group by deptno) d_avg
	 where e.sal > d_avg.d_a
	   and e.deptno = d_avg.deptno  

	--統計每年入職的員工個數
	select to_char(hiredate,'yyyy') hire_year,count(*) hire_count 
		  from emp  group by to_char(hiredate,'yyyy')
	--對結果集格式處理  先豎起來一列
	select decode(t.hire_year,'1987',t.hire_count) "1987" from 
	  (select to_char(hiredate,'yyyy') hire_year,count(*) hire_count 
		  from emp  group by to_char(hiredate,'yyyy') ) t
	--把空值的記錄過濾掉 聚合函數忽略空值的記錄
	select sum(decode(t.hire_year,'1987',t.hire_count)) "1987" from 
	  (select to_char(hiredate,'yyyy') hire_year,count(*) hire_count 
		  from emp  group by to_char(hiredate,'yyyy') ) t
	--補全其餘的列
	select sum(decode(t.hire_year,'1980',t.hire_count)) "1980",
		   max(decode(t.hire_year,'1981',t.hire_count)) "1981",
		   min(decode(t.hire_year,'1982',t.hire_count)) "1982",
		   avg(decode(t.hire_year,'1987',t.hire_count)) "1987"
	  from 
	  (select to_char(hiredate,'yyyy') hire_year,count(*) hire_count 
		  from emp  group by to_char(hiredate,'yyyy') ) t
	--使用sum對hire_count做求和運算補上total
	select sum(t.hire_count) total,
		   sum(decode(t.hire_year,'1980',t.hire_count)) "1980",
		   max(decode(t.hire_year,'1981',t.hire_count)) "1981",
		   min(decode(t.hire_year,'1982',t.hire_count)) "1982",
		   avg(decode(t.hire_year,'1987',t.hire_count)) "1987"
	  from 
	  (select to_char(hiredate,'yyyy') hire_year,count(*) hire_count 
		  from emp  group by to_char(hiredate,'yyyy') ) t
		  
	補充知識點:Oracle 中的分頁查詢
		ROWNUM:表示行号,實際上隻是一個列,但是這個列是一個僞列,此列可以在每張表中出
		現。
		ROWID:表中每行資料指向磁盤上的實體位址。
		  
	/*
	  集合的運算
		 交集 取兩個集合共同的部分 intersect A(1,2,3) B(2,3,4) A交B (2,3)
		 并集 取兩個集合最大的部分 union A(1,2,3) B(2,3,4) A并B (1,2,3,4)
								   union all                  A并B (1,2,3,2,3,4)
		 差集 從一個集合去掉另外一個集合剩餘的部分  minus A差B (1) 
	*/
	--範例:工資大于1500,或者是20部門下的員工
	--不使用集合實作
	select * from emp where sal>1500 or deptno=20
	--使用集合實作 --不包含重複記錄
	select * from emp where sal>1500
	union
	select * from emp where deptno=20
	--union all
	select * from emp where sal>1500
	union all
	select * from emp where deptno=20

	--範例:工資大于1500,并且是20部門下的員工
	select * from emp where sal>1500 and deptno=20
	--使用集合實作
	select * from emp where sal>1500
	intersect
	select * from emp where deptno=20

	--1981年入職的普通員工(不包括經理,總裁)  
	--使用以前知識實作
	select * from emp where '1981' = to_char(hiredate,'yyyy')
				  and job not in ('MANAGER','PRESIDENT')

	--使用集合實作
	select * from emp where '1981' = to_char(hiredate,'yyyy')
	minus         
	select * from emp where  job  in ('MANAGER','PRESIDENT')
	/*
	  集合的使用場景
		用于做跨表合并資料使用
	  合并資料規則
		必須合并的列的數量一緻  列的數值類型相同
	*/
	--查詢公司下所有的員工資訊
	select empno buisiness_no,ename  buisiness_name from emp
	union
	select mid,mname from manager;
	--資料類型不一緻不能合并
	select empno buisiness_no,ename  buisiness_name from emp
	union
	select mname,mid from manager;


	--上司表
	create table manager(
		   mid number(9),
		   mname varchar(10)
	)
	insert into manager values(1,'zs');
	insert into manager values(2,'lisi');
	commit;           

複制