什麼是PL/SQL
PL/SQL(Procedure Language/SQL)
PLSQL 是 Oracle 對 sql 語言的過程化擴展,指在 SQL 命令語言中增加了過程處理語句(如分
支、循環等),使 SQL 語言具有過程處理能力。把 SQL 語言的數據操縱能力與過程語言的數
據處理能力結合起來,使得 PLSQL 面向過程但比過程語言簡單、高效、靈活和實用。
PL/SQL的基本語法
DECLARE
聲明部分(變量聲明,光標聲明,例外聲明)
BEGIN
語句序列(DML語句...)
EXCEPTION
例外處理語句
END;
聲明部分
再把數據類型貼一下
變量的聲明方式爲先變量名,再變量類型
普通數據類型
--類型後面要跟上長度
var char(15);
-- :=就是賦值的意思,後面可以直接跟要賦的值
married boolean :=true;
-- number類型第一個參數爲精度,包括小數點後面的位數,第二個參數爲小數點後面的位數
psal number(7,2)
除了普通數據類型,還有引用數據類型
-- 引用型變量,即 my_name 的類型與 emp 表中 ename 列的類型一樣
emprec emp.ename%type;
--使用into對它進行賦值
declare
v_ename emp.ename%type;
begin
select e.ename into v_ename from emp e where e.empno = 7369;
dbms_output.put_line(v_ename);
end;
-- 記錄型變量,爲可以接受emp表一樣所有數據的對象
v_obj_emp emp%rowtype
-- 也是使用into進行賦值,注意,它只能接收到一行的數據,如果查詢結果爲多行或空,就會報錯
declare
v_obj_emp emp%rowtype;
begin
select * into v_obj_emp from emp e where e.empno = 7369;
dbms_output.put_line(v_obj_emp.ename || ' ' || v_obj_emp.sal);
end;
邏輯控制語句
if語句
-- if語句
declare
pnum number := # --&的功能爲從控制檯輸入 後面的num顯示在控制檯
begin
if pnum = 1 then
dbms_output.put_line('我是 1');
end if;
end;
-- if else 語句
declare
mynum number := #
begin
if mynum = 1 then
dbms_output.put_line('我是 1');
else
dbms_output.put_line('我不是 1');
end if;
end;
-- if elseif 語句
declare
mynum number := #
begin
if mynum < 18 then
dbms_output.put_line('未成年人');
elsif mynum >= 18 and mynum < 40 then
dbms_output.put_line('中年人');
elsif mynum >= 40 then
dbms_output.put_line('老年人');
end if;
end;
循環
-- while loop循環
declare
step number := 1;
begin
while step <= 10
loop
dbms_output.put_line(step);
step := step + 1;
end loop;
end;
-- loop exit when 循環
declare
step number := 1;
begin
loop
exit when step > 10;
dbms_output.put_line(step);
step := step + 1;
end loop;
end;
-- for循環
declare
step number := 1;
begin
for step in 1 .. 10
loop
dbms_output.put_line(step);
end loop;
end;
遊標
遊標可以理解爲java中的集合,用來儲存查詢返回的多條數據
語法
CURSOR 遊標名 [(參數名 數據類型,參數名 數據類型,...)] IS SELECT語句;
--中括號內爲可選,一般不用
遊標的使用步驟
0. 定義遊標和變量 cursor c1 is select ename from emp;
pjob emp.empjob%type;
- 打開遊標
open c1;
- 取一行遊標的值
fetch c1 into pjob;
- 當講所有值取出後關閉循環
exit when c1%notfound
- 關閉遊標,釋放資源
close c1;
例子,用遊標的方式輸出emp表中的員工編號和姓名
declare
cursor pc is select * from emp; --聲明遊標
pemp emp%rowtype; --聲明記錄型變量
begin
open pc; --開啓遊標
loop
fetch pc into pemp; --取出遊標每一行的數據
exit when pc%notfound; --當遊標所有數據被取出後,跳出循環
dbms_output.put_line(pemp.empno || ' ' || pemp.ename); -- 執行邏輯操作
end loop;
close pc;
end;
另一個例子,爲部門號爲10的員工漲工資
declare
cursor pc(dno myemp.deptno%type) is
select empno from myemp where deptno = dno; --聲明遊標
pno myemp.empno%type; --聲明記錄型變量
begin
open pc(20); --開啓遊標
loop
fetch pc into pno; --取出遊標的每一行數據賦值給變量
exit when pc%notfound; --當遊標所有值被取出,跳出循環
update myemp t set t.sal = t.sal + 1000 where t.empno =
pno; --執行邏輯命令
end loop;
close pc; --關閉遊標,釋放資源
end;
例外
異常是程序設計語言提供的一種功能,用來增強程序的健壯性和容錯性。Oracle PL/SQL中的異常就是例外
Oracle中內置了20000個例外,絕大多數需求都可以被滿足
比較常用的有
no_data_found (沒有找到數據)
too_many_rows (select …into 語句匹配多個行)
zero_divide ( 被零除)
value_error (算術或轉換錯誤)
timeout_on_resource (在等待資源時發生超時)
舉個栗子
declare
pnum number;
begin
pnum := 1 / 0;
exception
when zero_divide then
dbms_output.put_line('被0除');
when value_error then
dbms_output.put_line('數值轉換錯誤');
when others then
dbms_output.put_line('其他錯誤');
end;
此外,我們可以自定義例外,處理業務異常
看下面這個例子
declare
no_emp_found exception; --聲明一個例外
cursor pemp is
select t.ename from emp t where t.deptno = 50; --聲明瞭一個遊標
pename emp.ename%type; --聲明瞭一個記錄型變量
begin
open pemp;
fetch pemp into pename;
if pemp%notfound then
raise no_emp_found; --觸發在下面定義的 no_emp_found
end if;
close pemp;
exception
when no_emp_found then
dbms_output.put_line('沒有找到員工');
when others then
dbms_output.put_line('其他錯誤');
end;
需要注意的是,沒事使用自定義例外都要重新編寫,聲明
儲存過程
存儲過程(Stored Procedure)是在大型數據庫系統中,一組爲了完成特定功能的 SQL 語句集,經編譯後存儲在數據庫中,用戶通過指定存儲過程的名字並給出參數(如果該存儲過程帶有參數)來執行它。存儲過程是數據庫中的一個重要對象,任何一個設計良好的數據庫應用程序都應該用到存儲過程。
儲存過程就相當於java中封裝的方法;
創建格式如下
create [or replace] PROCEDURE 過程名[(名 參數名 in/out 數據類型)] AS
begin
PLSQL 子程序體; 子程序體;
End;
--或者
create [or replace] PROCEDURE 過程名[(名 參數名 in/out 數據類型)] is
定義儲存過程需要用到的變量
begin
PLSQL 子程序體; 子程序體;
End 過程名 過程名;
看這個例子 給員工變更工資 並打印 前後工資的情況
--參數要注意下,in爲輸入的參數,out爲輸出的參數,這個場景下,我們只需要進行數據輸入
--而且參數不需要寫數據類型的參數
--一般儘量使用CREATE OR REPLACE這樣就算改儲存過程已經存在,也可以進行更改
CREATE OR REPLACE PROCEDURE CHANGEEMPSALBYENPNO(ENO IN NUMBER,MON IN NUMBER)
IS
V_OLD_SAL EMP.SAL%TYPE;
V_NEW_SAL EMP.SAL%TYPE;
BEGIN
--查詢漲工資之前的工資情況,賦值給變量V_OLD_SAL;
SELECT E.SAL INTO V_OLD_SAL FROM EMP E
WHERE E.EMPNO=ENO;
--對該員工工資數據進行操作,並提交
UPDATE EMP SET SAL=SAL+MON where empno=eno;
COMMIT;
--再查詢一下變更之後的該員工工資
SELECT E.SAL INTO V_NEW_SAL FROM EMP E
WHERE E.EMPNO=ENO;
DBMS_OUTPUT.put_line('操作完成!');
dbms_output.put_line('漲工資之前:'||V_OLD_SAL);
dbms_output.put_line('漲工資之後'||V_NEW_SAL);
exception
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.put_line('沒有查詢到數據!');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.put_line('查詢返回多條結果!');
WHEN OTHERS THEN
dbms_output.put_line('系統未知錯誤!');
end;
--調用這個儲存過程非常簡單
begin
CHANGEEMPSALBYENPNO(7369,100);
end;
===========輸出結果==============
操作完成!
漲工資之前:800
漲工資之後900
儲存函數
儲存函數和儲存過程本質上沒區別。只是函數有限制只能返回一個標量,而存儲過程可以返回多個。並且函數是可以嵌入在SQL中使用的,可以在SELECT等SQL語句中調用,而存儲過程不行。執行的本質都一樣。
create or replace function 函數名(Name in type, Name out type, ...) return 型 數據類型 is
結果變量 數據類型;
begin
return( 結果變量);
end[ 函數名];