Oracle04
要求
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;
總之,Oracle優化不是一天的課題,你得在長期工作實踐中,進行反覆測試與總結,希望學員們日後好好領會
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;
總之,Oracle優化不是一天的課題,你得在長期工作實踐中,進行反覆測試與總結,希望學員們日後好好領會
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.