程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> Oracle數據庫 >> Oracle教程 >> Oracle學習(十一):PL/SQL

Oracle學習(十一):PL/SQL

編輯:Oracle教程

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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved