1.知識點:可以對照下面的錄屏進行閱讀
PL/SQL程序結構
declare
說明部分 (變量說明,光標申明,例外說明 〕
begin
語句序列 (DML語句〕…
exception
例外處理語句
End;
/
------------------------------------------------------------------
--第一個PL/SQL程序:HelloWorld
set serveroutput on --如果要在屏幕上輸出信息,需要將serveroutput開關打開
declare
--變量的說明
begin
--程序體
--程序包package
dbms_output.put_line('Hello World');
end;
/
------------------------------------------------------------------
--引用型變量: 查詢並打印7839的姓名和薪水
set serveroutput on
declare
--定義變量,
pename emp.ename%type; --將pename的類型設置為emp表中ename的類型
psal emp.sal%type; --將psal的類型設置為emp表中sal的類型
begin
--查詢:
--ename,sal into pename,psal:將查詢的ename,sal分別賦值給pename,psal按順序賦值
select ename,sal into pename,psal from emp where empno=7839;
--打印
dbms_output.put_line(pename||'的薪水是'||psal);
end;
/
------------------------------------------------------------------
--記錄型變量 查詢並打印7839的姓名和薪水
set serveroutput on
declare
--定義變量,代表一行
emp_rec emp%rowtype;
begin
--得到一行,賦值給emp_rec
select * into emp_rec from emp where empno=7839;
dbms_output.put_line(emp_rec.ename||'的薪水是'||emp_rec.sal);
end;
/
------------------------------------------------------------------
--if語句:判斷用戶輸入的數字
set serveroutput on
/*
1.提示信息
2. 接收鍵盤輸入
num 是一個地址值
SQL優化: num綁定變量(盡量使用綁定變量)
select * from emp where deptno=10; --> 執行計劃
select * from emp where deptno=20; --> 執行計劃
-->
select * from emp where deptno=#
*/
accept num prompt '請輸入一個數字';
declare
--變量保存輸入的數字
pnum number := #
begin
--判斷
if pnum = 0 then
dbms_output.put_line('您輸入的是0');
elsif pnum = 1 then
dbms_output.put_line('您輸入的是1');
elsif pnum = 2 then
dbms_output.put_line('您輸入的是2');
else
dbms_output.put_line('其他數字');
end if;
end;
/
------------------------------------------------------------------
--循環: 打印1~10,有3中方法,見下圖
set serveroutput on
declare
pnum number := 1; --給pnum賦值1,pnum類型為number
begin
loop
--退出:成立退出,不成立循環
exit when pnum > 10;
--隱式轉換,number轉varchar2
dbms_output.put_line(pnum);
pnum := pnum + 1;
end loop;
end;
/
------------------------------------------------------------------
光標(Cursor)==ResultSet
說明光標語法:
CURSOR 光標名 [ (參數名 數據類型[,參數名 數據類型]...)]
IS SELECT 語句;
用於存儲一個查詢返回的多行數據
例如:
cursor c1 is select ename from emp;
打開光標: open c1; (打開光標執行查詢)
取一行光標的值:fetch c1 into pjob; (取一行到變量中)
關閉光標: close c1;(關閉游標釋放資源)
注意: 上面的pjob必須與emp表中的job列類型一致:
定義:pjob emp.empjob%type;
------------------------------------------------------------------
--光標: 使用游標查詢員工姓名和工資,並打印
/*
光標的3個屬性:
%isopen 是否被打開:打開true,關閉false;
%rowcount 行數
%notfound 是否有值:沒有值true,有值false;
*/
set serveroutput on
declare
--光標
cursor cemp is select ename,sal from emp;
pename emp.ename%type; --將用來接收的變量類型設置為和查詢的類型相同
psal emp.sal%type;
begin
open cemp; --打開光標執行查詢
loop
--從集合中取值
fetch cemp into pename,psal;
--光標中沒有值時退出
exit when cemp%notfound;
dbms_output.put_line(pename||'的薪水是'||psal);
end loop;
close cemp;
end;
/
------------------------------------------------------------------
--光標練習:給員工漲工資 總裁1000 經理800 其他400
--光標同時能打開的最大數量默認為300個
/*
SQL> show parameters cursor
NAME TYPE VALUE
------------------------------------ ----------- --------
cursor_sharing string EXACT
cursor_space_for_time boolean FALSE
open_cursors integer 300
session_cached_cursors integer 20
*/
set serveroutput on
declare
--光標代表員工
cursor cemp is select empno,job from emp;
pempno emp.empno%type;
pjob emp.job%type;
begin
open cemp;
loop
fetch cemp into pempno,pjob;
exit when cemp%notfound;
--判斷
if pjob = 'PRESIDENT' then update emp set sal=sal+1000 where empno=pempno; --總裁漲1000
elsif pjob = 'MANAGER' then update emp set sal=sal+800 where empno=pempno; --經理漲800
else update emp set sal=sal+400 where empno=pempno; --其他漲400
end if;
end loop;
close cemp;
--提交: 隔離級別
commit;
dbms_output.put_line('完成');
end;
/
------------------------------------------------------------------
--帶參數的光標:查詢某個部門的員工姓名
set serveroutput on
declare
--定義一個帶參數的光標
cursor cemp(pdno number) is select ename from emp where deptno=pdno;
pename emp.ename%type;
begin
open cemp(20); --打開光標,並傳遞參數
loop
fetch cemp into pename;
exit when cemp%notfound;
dbms_output.put_line(pename);
end loop;
close cemp;
end;
/
------------------------------------------------------------------
Oracle的異常處理
1.系統定義例外
No_data_found (沒有找到數據)
Too_many_rows (select …into語句匹配多個行)
Zero_Divide ( 被零除)
Value_error (算術或轉換錯誤)
Timeout_on_resource (在等待資源時發生超時)
--舉例 Zero_Divide ( 被零除)
set serveroutput on
declare
pnum number;
begin
pnum := 1/0;
exception
when Zero_Divide then dbms_output.put_line('1: 0不能做被除數');
dbms_output.put_line('2: 0不能做被除數');
when Value_error then dbms_output.put_line('算術錯');
when others then dbms_output.put_line('其他例外');
end;
/
用戶自己定義的例外
--自定義例外: 查詢50號部門的員工姓名
set serveroutput on
declare
cursor cemp is select ename from emp where deptno=50;
pename emp.ename%type;
--自定義例外
no_emp_found exception;
begin
open cemp;
--取一個員工
fetch cemp into pename;
if cemp%notfound then
raise no_emp_found;
end if;
/*
if cemp%isopen then
close no_emp_found;
end if;
*/
close cemp;
exception
when no_emp_found then dbms_output.put_line('沒有找到員工');
when others then dbms_output.put_line('其他例外');
end;
/

圖:循環的3種寫法,文中采用右上角的方法。
2.在Sqlplus下實際執行的結果錄屏
SQL> --第一個PL/SQL程序:HelloWorld
SQL> set serveroutput on --如果要在屏幕上輸出信息,需要將serveroutput開關打開
SQL> declare
2 --變量的說明
3 begin
4 --程序體
5 --程序包package
6 dbms_output.put_line('Hello World');
7 end;
8 /
Hello World
PL/SQL procedure successfully completed
SQL>
SQL> --引用型變量: 查詢並打印7839的姓名和薪水
SQL> set serveroutput on
SQL> declare
2 --定義變量,
3 pename emp.ename%type; --將pename的類型設置為emp表中ename的類型
4 psal emp.sal%type; --將psal的類型設置為emp表中sal的類型
5
6 begin
7
8 --查詢:
9 --ename,sal into pename,psal:將查詢的ename,sal分別賦值給pename,psal按順序賦值
10 select ename,sal into pename,psal from emp where empno=7839;
11
12 --打印
13 dbms_output.put_line(pename||'的薪水是'||psal);
14
15 end;
16 /
KING的薪水是5000
PL/SQL procedure successfully completed
SQL>
SQL> -記錄型變量 查詢並打印7839的姓名和薪水
SQL> set serveroutput on
SQL> declare
2 --定義變量,代表一行
3 emp_rec emp%rowtype;
4 begin
5 --得到一行,賦值給emp_rec
6 select * into emp_rec from emp where empno=7839;
7
8 dbms_output.put_line(emp_rec.ename||'的薪水是'||emp_rec.sal);
9
10 end;
11 /
KING的薪水是5000
PL/SQL procedure successfully completed
SQL>
SQL> --if語句:判斷用戶輸入的數字
SQL> set serveroutput on
SQL> /*
2 1.提示信息
3 2. 接收鍵盤輸入
4 num 是一個地址值
5
6 SQL優化: num綁定變量(盡量使用綁定變量)
7 select * from emp where deptno=10; --> 執行計劃
8 select * from emp where deptno=20; --> 執行計劃
9 -->
10 select * from emp where deptno=#
11
12 */
13 accept num prompt '請輸入一個數字';
SQL> declare
2 --變量保存輸入的數字
3 pnum number := #
4 begin
5 --判斷
6 if pnum = 0 then
7 dbms_output.put_line('您輸入的是0');
8 elsif pnum = 1 then
9 dbms_output.put_line('您輸入的是1');
10 elsif pnum = 2 then
11 dbms_output.put_line('您輸入的是2');
12 else
13 dbms_output.put_line('其他數字');
14 end if;
15 end;
16 /
您輸入的是2
PL/SQL procedure successfully completed
SQL>
SQL> --循環: 打印1~10
SQL> set serveroutput on
SQL> declare
2 pnum number := 1; --給pnum賦值1,pnum類型為number
3 begin
4 loop
5 --退出:成立退出,不成立循環
6 exit when pnum > 10;
7
8 --隱式轉換,number轉varchar2
9 dbms_output.put_line(pnum);
10
11 pnum := pnum + 1;
12
13 end loop;
14 end;
15 /
1
2
3
4
5
6
7
8
9
10
PL/SQL procedure successfully completed
SQL>
SQL> -光標: 使用游標查詢員工姓名和工資,並打印
SQL> /*
2 光標的3個屬性:
3 %isopen 是否被打開:打開true,關閉false;
4 %rowcount 行數
5 %notfound 是否有值:沒有值true,有值false;
6 */
SQL> set serveroutput on
SQL> declare
2 --光標
3 cursor cemp is select ename,sal from emp;
4 pename emp.ename%type; --將用來接收的變量類型設置為和查詢的類型相同
5 psal emp.sal%type;
6 begin
7 open cemp; --打開光標執行查詢
8 loop
9 --從集合中取值
10 fetch cemp into pename,psal;
11 --光標中沒有值時退出
12 exit when cemp%notfound;
13
14 dbms_output.put_line(pename||'的薪水是'||psal);
15
16 end loop;
17 close cemp;
18 end;
19 /
SMITH的薪水是800
ALLEN的薪水是1600
WARD的薪水是1250
JONES的薪水是2975
MARTIN的薪水是1250
BLAKE的薪水是2850
CLARK的薪水是2450
SCOTT的薪水是3000
KING的薪水是5000
TURNER的薪水是1500
ADAMS的薪水是1100
JAMES的薪水是950
FORD的薪水是3000
MILLER的薪水是1300
PL/SQL procedure successfully completed
SQL> --光標練習:給員工漲工資 總裁1000 經理800 其他400
SQL> --先查詢沒漲之前的
SQL> select * from emp;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
7369 SMITH CLERK 7902 1980/12/17 800.00 20
7499 ALLEN SALESMAN 7698 1981/2/20 1600.00 300.00 30
7521 WARD SALESMAN 7698 1981/2/22 1250.00 500.00 30
7566 JONES MANAGER 7839 1981/4/2 2975.00 20
7654 MARTIN SALESMAN 7698 1981/9/28 1250.00 1400.00 30
7698 BLAKE MANAGER 7839 1981/5/1 2850.00 30
7782 CLARK MANAGER 7839 1981/6/9 2450.00 10
7788 SCOTT ANALYST 7566 1987/4/19 3000.00 20
7839 KING PRESIDENT 1981/11/17 5000.00 10
7844 TURNER SALESMAN 7698 1981/9/8 1500.00 0.00 30
7876 ADAMS CLERK 7788 1987/5/23 1100.00 20
7900 JAMES CLERK 7698 1981/12/3 950.00 30
7902 FORD ANALYST 7566 1981/12/3 3000.00 20
7934 MILLER CLERK 7782 1982/1/23 1300.00 10
14 rows selected
SQL> --執行PLSQL語句
SQL>
SQL> set serveroutput on
SQL> declare
2 --光標代表員工
3 cursor cemp is select empno,job from emp;
4 pempno emp.empno%type;
5 pjob emp.job%type;
6 begin
7 open cemp;
8 loop
9 fetch cemp into pempno,pjob;
10 exit when cemp%notfound;
11
12 --判斷
13 if pjob = 'PRESIDENT' then update emp set sal=sal+1000 where empno=pempno; --總裁漲1000
14 elsif pjob = 'MANAGER' then update emp set sal=sal+800 where empno=pempno; --經理漲800
15 else update emp set sal=sal+400 where empno=pempno; --其他漲400
16 end if;
17 end loop;
18 close cemp;
19
20 --提交: 隔離級別
21 commit;
22
23 dbms_output.put_line('完成');
24 end;
25 /
完成
PL/SQL procedure successfully completed
SQL> --查詢執行PLSQL語句後的薪水
SQL> select * from emp;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
7369 SMITH CLERK 7902 1980/12/17 1200.00 20
7499 ALLEN SALESMAN 7698 1981/2/20 2000.00 300.00 30
7521 WARD SALESMAN 7698 1981/2/22 1650.00 500.00 30
7566 JONES MANAGER 7839 1981/4/2 3775.00 20
7654 MARTIN SALESMAN 7698 1981/9/28 1650.00 1400.00 30
7698 BLAKE MANAGER 7839 1981/5/1 3650.00 30
7782 CLARK MANAGER 7839 1981/6/9 3250.00 10
7788 SCOTT ANALYST 7566 1987/4/19 3400.00 20
7839 KING PRESIDENT 1981/11/17 6000.00 10
7844 TURNER SALESMAN 7698 1981/9/8 1900.00 0.00 30
7876 ADAMS CLERK 7788 1987/5/23 1500.00 20
7900 JAMES CLERK 7698 1981/12/3 1350.00 30
7902 FORD ANALYST 7566 1981/12/3 3400.00 20
7934 MILLER CLERK 7782 1982/1/23 1700.00 10
14 rows selected
SQL> --對比漲之前,可以看出漲工資成功
SQL>
SQL> --帶參數的光標:查詢某個部門的員工姓名
SQL> set serveroutput on
SQL> declare
2 --定義一個帶參數的光標
3 cursor cemp(pdno number) is select ename from emp where deptno=pdno;
4 pename emp.ename%type;
5 begin
6 open cemp(20); --打開光標,並傳遞參數
7 loop
8 fetch cemp into pename;
9 exit when cemp%notfound;
10
11 dbms_output.put_line(pename);
12
13
14 end loop;
15 close cemp;
16 end;
17 /
SMITH
JONES
SCOTT
ADAMS
FORD
PL/SQL procedure successfully completed
SQL>
SQL> --舉例 Zero_Divide ( 被零除)
SQL> set serveroutput on
SQL> declare
2 pnum number;
3 begin
4
5 pnum := 1/0;
6
7 exception
8 when Zero_Divide then dbms_output.put_line('1: 0不能做被除數');
9 dbms_output.put_line('2: 0不能做被除數');
10 when Value_error then dbms_output.put_line('算術錯');
11 when others then dbms_output.put_line('其他例外');
12 end;
13 /
1: 0不能做被除數
2: 0不能做被除數
PL/SQL procedure successfully completed
SQL>
SQL> --自定義例外: 查詢50號部門的員工姓名
SQL> set serveroutput on
SQL> declare
2 cursor cemp is select ename from emp where deptno=50;
3 pename emp.ename%type;
4
5 --自定義例外
6 no_emp_found exception;
7 begin
8 open cemp;
9 --取一個員工
10 fetch cemp into pename;
11 if cemp%notfound then
12 raise no_emp_found;
13 end if;
14
15 close cemp;
16
17 exception
18 when no_emp_found then dbms_output.put_line('沒有找到員工');
19 when others then dbms_output.put_line('其他例外');
20
21 end;
22 /
沒有找到員工
PL/SQL procedure successfully completed
SQL> spool off
Stopped spooling to c:\PLSQL.txt