oracle數據庫03



-------------------------------------------------------------------------------------準備篇


col empno for 9999;
col ename for a10;
col job for a10;
col mgr for 9999;
col hiredate for a12;
col sal for 9999;
col comm for 9999;
col deptno for 99;
col tname for a40;
set pagesize 80;

--創建新表xxx_emp,複製emp表中的結構,同時複製emp表的所有數據
create table xxx_emp
as
select * from emp;


-------------------------------------------------------------------------------------增刪改數據


回顧SQL92/99標準的四大類
(1)DML(數據操縱語言):select,insert,update,delete
(2)DDL(數據定義語言):create table,alter table,drop table,truncate table
(3)DCL(數據控制語言):grant select any table to scott/revoke select any table from scott
(4)TCL(事務控制語言):commit,rollback,savepoint to 回滾點

向emp表中插入一條記錄(方式一:按表默認結構順序)insert into 表名 values ...語法
insert into emp values(1111,'JACK','IT',7788,sysdate,1000,100,40);

向emp表中插入一條記錄(方式二:按自定義順序)insert into 表名(列名) values ...語法
insert into emp(ENAME,EMPNO,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO)
values('MARRY',2222,'IT',7788,sysdate,1000,100,40);

向emp表中插入NULL值(方式一:採用顯示插入NULL值)
insert into emp values(3333,'SISI','IT',7788,sysdate,1000,NULL,40);

向emp表中插入NULL值 (方式二:採用隱式插入NULL值),前提是所插入的字段允許插入NULL值
insert into emp(ENAME,EMPNO,JOB,MGR,HIREDATE,SAL,DEPTNO)
values('SOSO',4444,'IT',7788,sysdate,1000,40);

使用&佔位符,動態輸入值,&可以運用在任何一個DML語句中,在values子句中使用,例如:'&ename'和&sal
insert into emp values(&empno,'&ename','&job',&mgr,&hiredate,&sal,&comm,&xxxxxxxx);
注意:&是sqlplus工具提供的佔位符,如果是字符串或日期型要加''符,數值型無需加''符

使用&佔位符,動態輸入值,&可以運用在任何一個DML語句中,在from子句中使用
select * from &table;

使用&佔位符,動態輸入值,&可以運用在任何一個DML語句中,在select子句中使用
select empno,ename,&colname from emp;

使用&佔位符,動態輸入值,&可以運用在任何一個DML語句中,在where子句中使用
select * from emp where sal > &money;

使用&佔位符,動態輸入值,&可以運用在任何一個DML語句中,在group by 和 having子句中使用
select deptno,avg(sal)
from emp
group by &deptno
having avg(sal) > &money;

刪除emp表中的所有記錄
delete from emp;

將xxx_emp表中所有20號部門的員工,複製到emp表中,批量插入,insert into 表名 select ...語法
insert into emp
select *
from xxx_emp
where deptno=20;

將'SMITH'的工資增加20%
update emp set sal=sal*1.2 where ename = upper('smith');

將'SMITH'的工資設置爲20號部門的平均工資,這是一個條件未知的事物,優先考慮子查詢
第一:20號部門的平均工資
      select avg(sal) from emp where deptno=20;
第二:將'SMITH'的工資設置爲2207
      update emp set sal=2207 where ename = 'SMITH';
子查詢:
     update emp
     set sal = (
    select avg(sal)
        from emp
        where deptno=20    
     )
     where ename = 'SMITH';   

刪除工資比所有部門平均工資都低的員工,這是一個條件未知的事物,優先考慮子查詢
第一:查詢所有部門的平均工資
      select avg(sal) from emp group by deptno;
第二:刪除工資比(*,*,*)都低的員工
      delete from emp where sal<all(*,*,*);
子查詢:
      delete
      from emp
      where sal < all(
     select avg(sal)
         from emp
         group by deptno
      );

刪除無佣金的員工
delete from emp where comm is null;

將emp表丟入回收站,drop table 表名
drop table emp;

從回收站將emp表閃回,flashback table 表名 to before drop
flashback table emp to before drop;

查詢回收站,show recyclebin
show recyclebin;

清空回收站,purge recyclebin
purge recyclebin;

使用關鍵字purge,徹底刪除emp表,即不會將emp表丟入回收站,永久刪除emp表,drop table 表名 purge
drop table emp purge;

依據xxx_emp表結構,創建emp表的結構,但不會插入數據
create table emp
as
select * from xxx_emp where 1<>1;

創建emp表,複製xxx_emp表中的結構,同時複製xxx_emp表的所有數據
create table emp
as
select * from xxx_emp where 1=1;
注意:where不寫的話,默認爲true

將emp截斷,再自動創建emp表,truncate table 表名
truncate table emp;

向emp表,批量插入來自xxx_emp表中部門號爲20的員工信息,只包括empno,ename,job,sal字段
insert into emp(empno,ename,job,sal)
select empno,ename,job,sal
from xxx_emp
where deptno=20;

使用關鍵字purge,徹底刪除emp表,即不會將emp表丟入回收站
drop table emp purge;

依據xxx_emp表,只創建emp表,但不復制數據,且emp表只包括empno,ename字段
create table emp(empno,ename)
as
select empno,ename from xxx_emp where 1=2;

向emp表(只含有empno和ename字段),批量插入xxx_emp表中部門號爲20的員工信息
insert into emp(empno,ename)
select empno,ename from xxx_emp where deptno=20;

drop table 和 truncate table 和 delete from 區別:
drop table
1)屬於DDL
2)不可回滾
3)不可帶where
4)表內容和結構刪除
5)刪除速度快

truncate table
1)屬於DDL
2)不可回滾
3)不可帶where
4)表內容刪除
5)刪除速度快

delete from
1)屬於DML
2)可回滾
3)可帶where
4)表結構在,表內容要看where執行的情況
5)刪除速度慢,需要逐行刪除
軟件工程師


-------------------------------------------------------------------------------------事務

回顧什麼是事務?
一個不可分割的子操作形成一個整體,該整體要麼全部執行成功,要麼全部執行失敗。例如:轉帳

回顧爲什麼要用事務?
如果不用事務的話,爲轉帳爲例,可能出現一個用戶錢增加了,另一個用戶錢不變

回顧編程中,事務可用於哪一層?
事務放在業務層

回顧jdbc編程中,如何使用事務?
connection.setAutoCommit(false);
pstmt.executeUpdate();
connection.commit();
connection.rollback();

回顧hibernate編程中,如何使用事務?
transaction.begin();
session.save(new User());
transaction.commit();
transaction.rollback();

回顧spring編程中,如何使用事務?
spring可以分爲二種
>編程式事務,藕合
>聲明式事務,解藕,提倡

Oracle的事務只針對DML操作,即select/insert/update/delete

回顧MySQL的事務開始:start transaction
Oracle的事務開始:第一條DML操作做爲事務開始

Oracle的提交事務
(1)顯示提交:commit    
(2)隱藏提交:DDL/DCL/exit(sqlplus工具)
注意:提交是的從事務開始到事務提交中間的內容,提交到ORCL數據庫中的DBF二進制文件

Oracle的回滾事務
(1)顯示回滾:rollback
(2)隱藏回滾:關閉窗口(sqlplus工具),死機,掉電
注意:回滾到事務開始的地方

回顧什麼是回滾點?
在操作之間設置的一個標誌位,用於將來回滾之用

回顧爲什麼要設置回滾點?savepoint a;rollback to savepoint a;
如果沒有設置回滾點的話,Oracle必須回滾到事務開始的地方,其間做的一個正確的操作也將撤銷

使用savepoint 回滾點,設置回滾點a    
savepoint a;

使用rollback to savepoint,回滾到回滾點a處
rollback to savepoint a;

Oracle提交或回滾後,原來設置的回滾點還有效嗎?
原回滾點無效了

Oracle之所以能回滾的原因是?
主要機制是實例池

回顧MySQL支持的四種事務隔離級別及能夠解決的問題
(1)read uncommitted -- 不能解決任何缺點
(2)read committed   -- 髒讀,Oracle默認
(3)reapatable read  -- 不可重複讀,髒讀,MySQL默認
(4)serializable     -- 幻讀,不可重複讀,髒讀,效率低

注意:jdbc/dbutils速度快,但書寫煩
      mybaits速度中等,但書寫"中等"
      hibernate速度慢,但書寫"爽"
      
Oracle支持的二種事務隔離級別及能夠解決的問題
Oracle支持:read committed 和 serializable

Oracle中設置事務隔離級別爲serializable
set transaction isolation level serializable;

演示二個用戶同時操作emp表,刪除KING這條記錄,會有什麼後果?
因爲有隔離級別的存在,所以不會出現二個用戶都刪除了KING這條記錄,
一定是一個用戶刪除KING成功,在該用戶沒有提交的情況下,另一個用戶等待


-------------------------------------------------------------------------------------訪問其它用戶下的對象


聲明:scott或hr叫用戶名/方案名/空間名
      scott--tiger
      hr-----lion
      
查詢當前用戶是誰
show user;

查詢scott自己表空間下的所有對象時,可加,或不加用戶名select * from emp;
select * from emp;

select * from scott.emp;

以sysdba身份解鎖hr普通帳戶
alter user hr account unlock;

以sysdba身份設置hr普通帳戶的密碼
alter user hr identified by lion;

當scott查詢hr表空間下的所有表時,必須得加用戶名
select * from hr.jobs;

在默認情況下,每個用戶只能查詢自已空間下的對象的權限,不能查詢其它用戶空間下的對象

以sysdba身份角色,授予scott用戶查詢所有用戶空間下的對象權限
grant select any table to scott;

以sysdba身份,撤銷scott用戶查詢所有用戶空間下的對象權限
revoke select any table from scott;

scott自已查看自己所擁有的權限
select * from user_sys_privs;

從scott用戶空間導航到sysdba用戶空間
conn / as sysdba;

從sysdba用戶空間導航到scott用戶空間
conn scott/tiger;

從scott用戶空間導航到hr用戶空間
conn hr/lion;

查詢hr用戶空間中的所有對象
select * from tab;

從hr用戶空間導航到scott用戶空間
conn scott/tiger;

在scott用戶空間下,查詢hr用戶空間下的jobs表,必須加上hr用戶空間名
select * from hr.jobs;


-------------------------------------------------------------------------------------視圖


什麼是視圖【View】
(1)視圖是一種虛表
(2)視圖建立在已有表的基礎上, 視圖賴以建立的這些表稱爲基表
(3)向視圖提供數據內容的語句爲 SELECT 語句,可以將視圖理解爲存儲起來的 SELECT 語句
(4)視圖向用戶提供基表數據的另一種表現形式
(5)視圖沒有存儲真正的數據,真正的數據還是存儲在基表中
(6)程序員雖然操作的是視圖,但最終視圖還會轉成操作基表
(7)一個基表可以有0個或多個視圖

什麼情況下會用到視圖
(1)如果你不想讓用戶看到所有數據(字段,記錄),只想讓用戶看到某些的數據時,此時可以使用視圖
(2)當你需要減化SQL查詢語句的編寫時,可以使用視圖,但不提高查詢效率

視圖應用領域
(1)銀行,電信,金屬,證券軍事等不便讓用戶知道所有數據的項目中

視圖的作用
(1)限制數據訪問
(2)簡化複雜查詢
(3)提供數據的相互獨立
(4)同樣的數據,可以有不同的顯示方式

基於emp表所有列,創建視圖emp_view_1,create view 視圖名 as select對一張或多張基表的查詢
create view emp_view_1
as
select * from emp;

默認情況下,普通用戶無權創建視圖,得讓sysdba爲你分配creare view的權限

以sysdba身份,授權scott用戶create view權限
grant create view to scott;

以sysdba身份,撤銷scott用戶create view權限
revoke create view from scott;

基於emp表指定列,創建視圖emp_view_2,該視圖包含編號/姓名/工資/年薪/年收入(查詢中使用列別名)
create view emp_view_2
as
select empno "編號",ename "姓名",sal "工資",sal*12 "年薪",sal*12+NVL(comm,0) "年收入"
from emp;

基於emp表指定列,創建視圖emp_view_3(a,b,c,d,e),包含編號/姓名/工資/年薪/年收入(視圖中使用列名)
create view emp_view_3(a,b,c,d,e)
as
select empno "編號",ename "姓名",sal "工資",sal*12 "年薪",sal*12+NVL(comm,0) "年收入"
from emp;

查詢emp_view_3創建視圖的結構
desc emp_view_3;

修改emp_view_3(id,name,salary,annual,income)視圖,create or replace view 視圖名 as 子查詢
create or replace view emp_view_3(id,name,salary,annual,income)
as
select empno "編號",ename "姓名",sal "工資",sal*12 "年薪",sal*12+NVL(comm,0) "年收入"
from emp;

查詢emp表,求出各部門的最低工資,最高工資,平均工資
select min(sal),max(sal),round(avg(sal),0),deptno
from emp
group by deptno;

創建視圖emp_view_4,視圖中包含各部門的最低工資,最高工資,平均工資
create or replace view emp_view_4
as
select deptno "部門號",min(sal) "最低工資",max(sal) "最高工資",round(avg(sal),0) "平均工資"
from emp
group by deptno;

創建視圖emp_view_5,視圖中包含員工編號,姓名,工資,部門名,工資等級
create or replace view emp_view_5
as
select e.empno "編號",e.ename "姓名",e.sal "工資",d.dname "部門名",s.grade "工資等級"
from emp e,dept d,salgrade s
where (e.deptno=d.deptno) and (e.sal between s.losal and s.hisal);

刪除視圖emp_view_1中的7788號員工的記錄,使用delete操作,會影響基表嗎
delete from emp_view_1 where empno=7788;寫法正確,會影響基表

修改emp_view_1爲只讀視圖【with read only】,再執行上述delete操作,還行嗎?
create or replace view emp_view_1
as
select * from emp
with read only;
不能進行delete操作了

刪除視圖中的【某條】記錄會影響基表嗎?
會影響基表

將【整個】視圖刪除,會影響表嗎?
不會影響基表

刪除視圖,會進入回收站嗎?
不會進入回收站

刪除基表會影響視圖嗎?
會影響視圖

閃回基表後,視圖有影響嗎?
視圖又可以正常工作了


-------------------------------------------------------------------------------------同義詞


什麼是同義詞【Synonym】
(1)對一些比較長名字的對象(表,視圖,索引,序列,。。。)做減化,用別名替代

同義詞的作用
(1)縮短對象名字的長度
(2)方便訪問其它用戶的對象

創建與salgrade表對應的同義詞,create synonym 同義詞 for 表名/視圖/其它對象
create synonym e for salgrade;
create synonym ev5 for emp_view_5;

以sys身份授予scott普通用戶create synonym權限
grant create synonym to scott;

以sys身份從scott普通用戶撤銷create synonym權限
revoke create synonym from scott;

使用同義詞操作salgrade表
select * from s;

刪除同義詞
drop synonym ev5;

刪除同義詞,會影響基表嗎?
不會影響基表

刪除基表,會影響同義詞嗎?
會影響同義詞


-------------------------------------------------------------------------------------序列


什麼是序列【Sequence】
(1)類似於MySQL中的auto_increment自動增長機制,但Oracle中無auto_increment機制
(2)是oracle提供的一個產生唯一數值型值的機制
(3)通常用於表的主健值
(4)序列只能保證唯一,不能保證連續
     聲明:oracle中,只有rownum永遠保持從1開始,且繼續
(5)序列值,可放於內存,取之較快
 
題問:爲什麼oracle不直接用rownum做主健呢?
rownum=1這條記錄不能永遠唯一表示SMITH這個用戶
但主鍵=1確可以永遠唯一表示SMITH這個用戶

爲什麼要用序列
(1)以前我們爲主健設置值,需要人工設置值,容易出錯
(2)以前每張表的主健值,是獨立的,不能共享

爲emp表的empno字段,創建序列emp_empno_seq,create sequence 序列名
create sequence emp_empno_seq;

刪除序列emp_empno_seq,drop sequence 序列名
drop sequence emp_empno_seq;

查詢emp_empno_seq序列的當前值currval和下一個值nextval,第一次使用序列時,必須選用:序列名.nextval
select emp_empno_seq.nextval from dual;
select emp_empno_seq.currval from dual;

使用序列,向emp表插入記錄,empno字段使用序列值
insert into emp(empno) values(emp_empno_seq.nextval);
insert into emp(empno) values(emp_empno_seq.nextval);
insert into emp(empno) values(emp_empno_seq.nextval);

修改emp_empno_seq序列的increment by屬性爲20,默認start with是1,alter sequence 序列名
alter sequence emp_empno_seq
increment by 20;

修改修改emp_empno_seq序列的的increment by屬性爲5
alter sequence emp_empno_seq
increment by 5;

修改emp_empno_seq序列的start with屬性,行嗎
alter sequence emp_empno_seq
start with 100;

有了序列後,還能爲主健手工設置值嗎?
insert into emp(empno) values(9999);
insert into emp(empno) values(7900);

刪除表,會影響序列嗎?
你無法做insert操作

刪除序列,會影響表嗎?
表真正亡,序列亡

在hibernate中,如果是訪問oracle數據庫服務器,那麼User.hbm.xml映射文件中關於<id>標籤如何配置呢?
<id name="id" column="id">
   <generator class="increment/identity/uuid/【sequence】/【native】"/>
</id>


-------------------------------------------------------------------------------------索引


什麼是索引【Index】
(1)是一種快速查詢表中內容的機制,類似於新華字典的目錄
(2)運用在表中某個/些字段上,但存儲時,獨立於表之外

爲什麼要用索引
(1)通過指針加速Oracle服務器的查詢速度
(2)通過rowid快速定位數據的方法,減少磁盤I/O
     rowid是oracle中唯一確定每張表不同記錄的唯一身份證

rowid的特點
(1)位於每個表中,但表面上看不見,例如:desc emp是看不見的
(2)只有在select中,顯示寫出rowid,方可看見
(3)它與每個表綁定在一起,表亡,該表的rowid亡,二張表rownum可以相同,但rowid必須是唯一的
(4)rowid是18位大小寫加數字混雜體,唯一表代該條記錄在DBF文件中的位置
(5)rowid可以參與=/like比較時,用''單引號將rowid的值包起來,且區分大小寫
(6)rowid是聯繫表與DBF文件的橋樑

索引的特點
(1)索引一旦建立, Oracle管理系統會對其進行自動維護, 而且由Oracle管理系統決定何時使用索引
(2)用戶不用在查詢語句中指定使用哪個索引
(3)在定義primary key或unique約束後系統自動在相應的列上創建索引
(4)用戶也能按自己的需求,對指定單個字段或多個字段,添加索引

什麼時候【要】創建索引
(1)表經常進行 SELECT 操作
(2)表很大(記錄超多),記錄內容分佈範圍很廣
(3)列名經常在 WHERE 子句或連接條件中出現
 注意:符合上述某一條要求,都可創建索引,創建索引是一個優化問題,同樣也是一個策略問題
       
什麼時候【不要】創建索引
(1)表經常進行 INSERT/UPDATE/DELETE 操作
(2)表很小(記錄超少)
(3)列名不經常作爲連接條件或出現在 WHERE 子句中
同上注意

爲emp表的empno單個字段,創建索引emp_empno_idx,叫單列索引,create index 索引名 on 表名(字段,...)
create index emp_empno_idx
on emp(empno);

爲emp表的ename,job多個字段,創建索引emp_ename_job_idx,多列索引/聯合索引
create index emp_ename_job
on emp(ename,job);
如果在where中只出現job不使用索引
如果在where中只出現ename使用索引
我們提倡同時出現ename和job

注意:索引創建後,只有查詢表有關,和其它(insert/update/delete)無關,解決速度問題

刪除emp_empno_idx和emp_ename_job_idx索引,drop index 索引名
drop index emp_empno_idx;
drop index emp_ename_job_idx;

要求

1)掌握PLSQL程序設計

2)掌握存儲過程,函數和觸發器

3)瞭解一些oralceSQL語句優化方案


-------------------------------------------------------------------------------------準備篇


col empno for 9999;
col ename for a10;
col job for a10;
col mgr for 9999;
col hiredate for a12;
col sal for 9999;
col comm for 9999;
col deptno for 99;
col tname for a40;
set pagesize 80;


-------------------------------------------------------------------------------------SQL對比PLSQL


SQL99是什麼
(1)是操作所有關係型數據庫的規則
(2)是第四代語言
(3)是一種結構化查詢語言
(4)只需發出合法合理的命令,就有對應的結果顯示

SQL的特點
(1)交互性強,非過程化
(2)數據庫操縱能力強,只需發送命令,無需關注如何實現
(3)多表操作時,自動導航簡單,例如:
     select emp.empno,emp.sal,dept.dname
     from emp,dept
     where emp.deptno = dept.deptno
(4)容易調試,錯誤提示,直接了當
(5)SQL強調結果

PLSQL是什麼
     是專用於Oracle服務器,在SQL基礎之上,添加了一些過程化控制語句,叫PLSQL
     過程化包括有:類型定義,判斷,循環,遊標,異常或例外處理。。。
     PLSQL強調過程

爲什麼要用PLSQL
     因爲SQL是第四代命令式語言,無法顯示處理過程化的業務,所以得用一個過程化程序設計語言來彌補SQL的不足之處,
     SQL和PLSQL不是替代關係,是彌補關係        
        
PLSQL程序的完整組成結構如下:
     [declare]
          變量聲明;
        變量聲明;
     begin
          DML/TCL操作;
      DML/TCL操作;
     [exception]
          例外處理;
      例外處理;
     end;
     /
注意:在PLSQL程序中,;號表示每條語句的結束,/表示整個PLSQL程序結束

書寫PLSQL的工具有:
(1)SQLPLUS工具
(2)SQLDeveloper工具
(3)第三方工具(PLSQL & 其它)

PLSQL與SQL執行有什麼不同:
(1)SQL是單條執行的
(2)PLSQL是整體執行的,不能單條執行,整個PLSQL結束用/,其中每條語句結束用;號


------------------------------------------------------------------------------------PLSQL類型


寫一個PLSQL程序,輸出"hello world"字符串,語法:dbms_output.put_line('需要輸出的字符串');
begin
    --向SQLPLUS客戶端工具輸出字符串
    dbms_output.put_line('hello 你好');
end;
/

注意:
dbms_output是oracle中的一個輸出對象
put_line是上述對象的一個方法,用於輸出一個字符串自動換行

設置顯示PLSQL程序的執行結果,默認情況下,不顯示PLSQL程序的執行結果,語法:set serveroutput on/off;
set serveroutput on;

使用基本類型變量,常量和註釋,求10+100的和
declare
    --定義變量
    mysum number(3) := 0;
    tip varchar2(10) := '結果是';
begin
    /*業務算法*/   
    mysum := 10 + 100;
    /*輸出到控制器*/
    dbms_output.put_line(tip || mysum);
end;
/

輸出7369號員工姓名和工資,格式如下:7369號員工的姓名是SMITH,薪水是800,語法:使用表名.字段%type
declare
    --定義二個變量,分別裝姓名和工資
    pename emp.ename%type;
    psal   emp.sal%type;
begin  
    --SQL語句
    --select ename,sal from emp where empno = 7369;
    --PLSQL語句,將ename的值放入pename變量中,sal的值放入psal變量中    
    select ename,sal into pename,psal from emp where empno = 7369;
    --輸出
    dbms_output.put_line('7369號員工的姓名是'||pename||',薪水是'||psal);    
end;
/

輸出7788號員工姓名和工資,格式如下:7788號員工的姓名是SMITH,薪水是3000,語法:使用表名%rowtype
declare
    emp_record emp%rowtype;
begin
    select * into emp_record from emp where empno = 7788;
    dbms_output.put_line('7788號員工的姓名是'||emp_record.ename||',薪水是'||emp_record.sal);
end;
/

何時使用%type,何時使用%rowtype?
當定義變量時,該變量的類型與表中某字段的類型相同時,可以使用%type
當定義變量時,該變量與整個表結構完全相同時,可以使用%rowtype,此時通過變量名.字段名,可以取值變量中對應的值
項目中,常用%type


------------------------------------------------------------------------------------PLSQL判斷


使用if-else-end if顯示今天星期幾,是"工作日"還是"休息日"
declare
    pday varchar2(10);
begin
    select to_char(sysdate,'day') into pday from dual;
    dbms_output.put_line('今天是'||pday);
    if pday in ('星期六','星期日') then
    dbms_output.put_line('休息日');
    else
    dbms_output.put_line('工作日');
    end if;
end;
/

從鍵盤接收值,使用if-elsif-else-end if顯示"age<16","age<30","age<60","age<80"
declare
    age number(3) := &age;
begin
    if age < 16 then
       dbms_output.put_line('你未成人');
    elsif age < 30 then
       dbms_output.put_line('你青年人');
    elsif age < 60 then
       dbms_output.put_line('你奮鬥人');
    elsif age < 80 then
       dbms_output.put_line('你享受人');
    else
       dbms_output.put_line('未完再繼');
    end if;
end;
/


-------------------------------------------------------------------------------------PLSQL循環


使用loop循環顯示1-10
declare
    i number(2) := 1;
begin
    loop
        --當i>10時,退出循環
        exit when i>10;
        --輸出i的值
        dbms_output.put_line(i);
        --變量自加
        i := i + 1;  
    end loop;
end;
/

使用while循環顯示1-10
declare
    i number(2) := 1;
begin
    while i<11
    loop
        dbms_output.put_line(i);
        i := i + 1;
    end loop;
end;
/

使用while循環,向emp表中插入999條記錄
declare
    i number(4) := 1;
begin
    while( i < 1000 )
    loop
        insert into emp(empno,ename) values(i,'哈哈');
        i := i + 1;
    end loop;   
end;
/

使用while循環,從emp表中刪除999條記錄
declare
    i number(4) := 1;
begin
    while i<1000
    loop
        delete from emp where empno = i;
        i := i + 1;
    end loop;
end;
/

使用for循環顯示20-30
declare
    i number(2) := 20;
begin
    for i in 20 .. 30
    loop
        dbms_output.put_line(i);
    end loop;
end;
/


-------------------------------------------------------------------------------------PLSQL遊標


什麼是光標/遊標/cursor
類似於JDBC中的ResultSet對象的功能,從上向下依次獲取每一記錄的內容

使用無參光標cursor,查詢所有員工的姓名和工資【如果需要遍歷多條記錄時,使用光標cursor,無記錄找到使用cemp%notfound】
declare
    --定義遊標
    cursor cemp is select ename,sal from emp;
    --定義變量
    vename emp.ename%type;
    vsal   emp.sal%type;
begin
    --打開遊標,這時遊標位於第一條記錄之前
    open cemp;
    --循環
    loop
       --向下移動遊標一次
       fetch cemp into vename,vsal;
       --退出循環,當遊標下移一次後,找不到記錄時,則退出循環
       exit when cemp%notfound;
       --輸出結果
       dbms_output.put_line(vename||'--------'||vsal);
    end loop;
    --關閉遊標
    close cemp;
end;
/

使用帶參光標cursor,查詢10號部門的員工姓名和工資
declare
    cursor cemp(pdeptno emp.deptno%type) is select ename,sal from emp where deptno=pdeptno;
    pename emp.ename%type;
    psal emp.sal%type;
begin
    open cemp(&deptno);
    loop
        fetch cemp into pename,psal;    
        exit when cemp%notfound;
        dbms_output.put_line(pename||'的薪水是'||psal);
    end loop;
    close cemp;
end;
/

使用無參光標cursor,真正給員工漲工資,ANALYST漲1000,MANAGER漲800,其它漲400,要求顯示編號,姓名,職位,薪水
declare
    cursor cemp is select empno,ename,job,sal from emp;
    pempno emp.empno%type;
    pename emp.ename%type;
    pjob   emp.job%type;
    psal   emp.sal%type;
begin
    open cemp;
    loop
        fetch cemp into pempno,pename,pjob,psal;
        --循環退出條件一定要寫
        exit when cemp%notfound;
        if pjob='ANALYST' then
            update emp set sal = sal + 1000 where empno = pempno;
        elsif pjob='MANAGER' then
            update emp set sal = sal + 800 where empno = pempno;
        else
        update emp set sal = sal + 400 where empno = pempno;
        end if;
    end loop;
    commit;
    close cemp;
end;
/


-------------------------------------------------------------------------------------PLSQL例外


使用oracle系統內置例外,演示除0例外【zero_divide】
declare
    myresult number;
begin
    myresult := 1/0;
    dbms_output.put_line(myresult);
exception
    when zero_divide then
     dbms_output.put_line('除數不能爲0');
     delete from emp;  
end;
/

使用oracle系統內置例外,查詢100號部門的員工姓名,演示沒有找到數據【no_data_found】
declare
    pename varchar2(20);
begin
    select ename into pename from emp where deptno = 100;
    dbms_output.put_line(pename);
exception
    when NO_DATA_FOUND then
     dbms_output.put_line('查無該部門員工');
     insert into emp(empno,ename) values(1111,'ERROR');
end;
/

使用用戶自定義例外,使用光標cursor,查詢10/20/30/100號部門的員工姓名,演示沒有找到數據【nohave_emp_found】


------------------------------------------------------------------------------------存儲過程概念


什麼是存儲過程【procedure】?

爲什麼要用存儲過程?
    (1)PLSQL每次執行都要整體運行一遍,纔有結果
    (2)PLSQL不能將其封裝起來,長期保存在oracle服務器中
    (3)PLSQL不能被其它應用程序調用,例如:Java

存儲過程與PLSQL是什麼關係?


--------------------------------------------------------存儲過程


創建無參存儲過程hello,無返回值,語法:create or replace procedure 過程名 as PLSQL程序

刪除存儲過程hello,語法:drop procedure 過程名

調用存儲過程方式一,exec 存儲過程名

調用存儲過程方式二,PLSQL程序

調用存儲過程方式三,Java程序

創建有參存儲過程raiseSalary(編號),爲7369號員工漲10%的工資,演示in的用法,默認in,大小寫不敏感

創建有參存儲過程findEmpNameAndSalAndJob(編號),查詢7788號員工的的姓名,職位,月薪,返回多個值,演示out的用法

什麼情況下用exec調用,什麼情況下用PLSQL調用存儲過程?

用存儲過程,寫一個計算個人所得稅的功能


-------------------------------------------------------------------------------------存儲函數


創建無參存儲函數getName,有返回值,語法:create or replace function 函數名 return 返回類型 as PLSQL程序段

刪除存儲函數getName,語法:drop function 函數名

調用存儲函數方式一,PLSQL程序

調用存儲函數方式二,Java程序

創建有參存儲函數findEmpIncome(編號),查詢7369號員工的年收入,演示in的用法,默認in

創建有參存儲函數findEmpNameAndJobAndSal(編號),查詢7788號員工的的姓名(return),職位(out),月薪(out),返回多個值


-------------------------------------------------------------------------------------過程函數適合場景


聲明:適合不是強行要你使用,只是優先考慮

什麼情況下【適合使用】存儲過程?什麼情況下【適合使用】存儲函數?

【適合使用】存儲過程:

【適合使用】存儲函數:
        
什麼情況【適合使用】過程函數,什麼情況【適合使用】SQL?

【適合使用】過程函數:
        》需要長期保存在數據庫中
            》需要被多個用戶重複調用
            》業務邏輯相同,只是參數不一樣
        》批操作大量數據,例如:批量插入很多數據

【適合使用】SQL:
        》凡是上述反面,都可使用SQL
        》對錶,視圖,序列,索引,等這些還是要用SQL

                
-------------------------------------------------------------------------------------觸發器


什麼是觸發器【Trigger】?

爲什麼要用觸發器?

創建語句級觸發器insertEmpTrigger,當對錶【emp】進行增加【insert】操作前【before】,顯示"hello world"

刪除觸發器insertEmpTrigger,語法:drop trigger 觸發器名

使用insert語句插入一條記錄,引起insertEmpTrigger觸發器工作

使用insert語句插入N條記錄,引起insertEmpTrigger觸發器工作

創建語句級觸發器deleteEmpTrigger,當對錶【emp】進行刪除【delete】操作後【after】,顯示"world hello"

使用delete語句刪除一條記錄,引起deleteEmpTrigger觸發器工作

使用delete語句刪除N條記錄,引起deleteEmpTrigger觸發器工作

星期一到星期五,且9-20點能向數據庫emp表插入數據,否則使用函數拋出異常,
語法:raise_application_error('-20000','例外原因')

創建行級觸發器checkSalaryTrigger,漲後工資這一列,確保大於漲前工資,語法:for each row/:new.sal/:old.sal

刪除觸發器,表還在嗎?

將表丟到回收站,觸發器還在嗎?

當閃回表後,觸發器會在嗎?

徹底刪除表,觸發器會在嗎?


-------------------------------------------------------------------------------------oracleSQL優化方案


爲什麼要Oracle優化:
       隨着實際項目的啓動,Oracle經過一段時間的運行,最初的Oracle設置,會與實際Oracle運行性能會有一些差異,這時我們       就需要做一個優化調整。

Oracle優化這個課題較大,可分爲四大類:
       》主機性能
       》內存使用性能
       》網絡傳輸性能
       》SQL語句執行性能【程序員】

下面列出一些oracleSQL優化方案:


(01)選擇最有效率的表名順序(筆試常考)
      ORACLE的解析器按照從右到左的順序處理FROM子句中的表名,
      FROM子句中寫在最後的表將被最先處理,
      在FROM子句中包含多個表的情況下,你必須選擇記錄條數最少的表放在最後,
      如果有3個以上的表連接查詢,那就需要選擇那個被其他表所引用的表放在最後。
      例如:查詢員工的編號,姓名,工資,工資等級,部門名
      select emp.empno,emp.ename,emp.sal,salgrade.grade,dept.dname
      from salgrade,dept,emp
      where (emp.deptno = dept.deptno) and (emp.sal between salgrade.losal and salgrade.hisal)          
      1)如果三個表是完全無關係的話,將記錄和列名最少的表,寫在最後,然後依次類推
      2)如果三個表是有關係的話,將引用最多的表,放在最後,然後依次類推


(02)WHERE子句中的連接順序(筆試常考)  
      ORACLE採用自右而左的順序解析WHERE子句,根據這個原理,表之間的連接必須寫在其他WHERE條件之左,
      那些可以過濾掉最大數量記錄的條件必須寫在WHERE子句的之右。  
      例如:查詢員工的編號,姓名,工資,部門名  
      select emp.empno,emp.ename,emp.sal,dept.dname
      from emp,dept
      where (emp.deptno = dept.deptno) and (emp.sal > 1500)   
      
(03)SELECT子句中避免使用*號
      ORACLE在解析的過程中,會將*依次轉換成所有的列名,這個工作是通過查詢數據字典完成的,這意味着將耗費更多的時間
      select empno,ename from emp;

(04)使用DECODE函數來減少處理時間
      使用DECODE函數可以避免重複掃描相同記錄或重複連接相同的表

(05)整合簡單,無關聯的數據庫訪問

(06)用TRUNCATE替代DELETE
   
(07)儘量多使用COMMIT
      因爲COMMIT會釋放回滾點

(08)用WHERE子句替換HAVING子句
      WHERE先執行,HAVING後執行
     
(09)多使用內部函數提高SQL效率
     
(10)使用表的別名
      salgrade s
     
(11)使用列的別名
      ename e

(12)用索引提高效率
      在查詢中,善用索引
      
(13)字符串型,能用=號,不用like
      因爲=號表示精確比較,like表示模糊比較

(14)SQL語句用大寫的
      因爲Oracle服務器總是先將小寫字母轉成大寫後,才執行
      在eclipse中,先寫小寫字母,再通過ctrl+shift+X轉大寫;ctrl+shift+Y轉小寫    

(15)避免在索引列上使用NOT
      因爲Oracle服務器遇到NOT後,他就會停止目前的工作,轉而執行全表掃描

(16)避免在索引列上使用計算
      WHERE子句中,如果索引列是函數的一部分,優化器將不使用索引而使用全表掃描,這樣會變得變慢
      例如,SAL列上有索引,
      低效:
      SELECT EMPNO,ENAME
      FROM EMP
      WHERE SAL*12 > 24000;
      高效:
      SELECT EMPNO,ENAME
      FROM EMP
      WHERE SAL > 24000/12;

(17)用 >= 替代 >
      低效:
      SELECT * FROM EMP WHERE DEPTNO > 3   
      首先定位到DEPTNO=3的記錄並且掃描到第一個DEPT大於3的記錄
      高效:
      SELECT * FROM EMP WHERE DEPTNO >= 4  
      直接跳到第一個DEPT等於4的記錄

(18)用IN替代OR
      select * from emp where sal = 1500 or sal = 3000 or sal = 800;
      select * from emp where sal in (1500,3000,800);

(19)總是使用索引的第一個列
      如果索引是建立在多個列上,只有在它的第一個列被WHERE子句引用時,優化器纔會選擇使用該索引
      當只引用索引的第二個列時,不引用索引的第一個列時,優化器使用了全表掃描而忽略了索引
      create index emp_sal_job_idex
      on emp(sal,job);
      ----------------------------------
      select *
      from emp  
      where job != 'SALES';          

(20)避免改變索引列的類型,顯示比隱式更安全
      當字符和數值比較時,ORACLE會優先轉換數值類型到字符類型
      select 123 || '123' from dual;
      
    









































發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章