PL/SQL 總結,plsql總結

來源:互聯網
上載者:User

PL/SQL 總結,plsql總結
一、.基本文法
PL/SQL的結構塊如下:
declare
      --聲明變數、類型、遊標 
begin
        --程式執行的部分,類似main方法
exception
        --針對異常,提供如何處理的機制
        --when ....then....
end;
注意,沒有用的部分,就 不需要寫,比如程式的確是沒有異常要處理,那麼exception就不寫
建議的命名方法:
標識符  命名規則 例子
程式變數  V_name V_name
程式常量  C_Name C_company_name
遊標變數          Name_cursor Emp_cursor
異常標識  E_name E_too_many
表類型  Name_table_typeEmp_record_type
表  Name_table Emp
記錄類型  Name_recordEmp_record
SQL*Plus替代變數  P_name P_sal
綁定變數  G_name G_year_sal
HelloWorld示範:

begin  dbms_output.put_line('HelloWorld');end;
輸出100員工的工資:
declare  v_sal number(20) :=0;    --聲明變數,要注意的是,資料類型和要查詢的表中的資料類型是對應得  --附一個預設值,:=   v_email varchar2(20);--另一種寫法,v_email employees.email % type  v_hire_date date;    --v_hire_date employees.hire_date % type   //v_hire_date與employees表中的hire_date類型一樣--%type ,如果自訂類型的精度不夠,那麼%type就是動態擷取表中的類型及精度begin   select salary,email , hire_date into v_sal,v_email,v_hire_date   from employees where employee_id = 100;  --實現select操作,注意是select into  dbms_output.put_line(v_sal||','||v_email||','||v_hire_date);--列印end;
修改資料
declare     v_emp_id employees.employee_id%type;begin     v_emp_id :=100;     update employees     set salary = salary + 100     where employee_id = v_emp_id;     dbms_output.put_line('OK');end; 
使用%TYPE
定義一個變數,其資料類型與已經定義的某個 資料變數的類型相同,或者與資料庫表的某個列的資料類型
相同,這時可以使用%TYPE。
使用%TYPE 特性的優點在於:
  所引用的資料庫列的資料類型可以不必知道;
  所引用的資料庫列的資料類型可以即時改變。
使用%ROWTYPE
PL/SQL 提供%ROWTYPE  操作符,  返回一個記錄類型,  其資料類型和資料庫表的資料結構相一致。
使用%ROWTYPE 特性的優點在於:
  所引用的資料庫中列的個數和資料類型可以不必知道;
  所引用的資料庫中列的個數和資料類型可以即時改變。
二、記錄類型
type ... is record(,,);
DECLARE  --聲明一個記錄類型,類似於java中的類 TYPE emp_record IS RECORD(      v_sal employees.salary % type,      v_email employees.email % type,--以逗號連結      v_hire_date employees.hire_date % type);--分號   --定義一個記錄變數   v_emp_record emp_record;BEGIN      SELECT salary , email, hire_date INTO v_emp_record      FROM employees WHERE employee_id = 101;      dbms_output.put_line(v_emp_record.v_sal||','||v_emp_record.v_email||','||v_emp_record.v_hire_date);END;
擷取一個表中所有列的記錄類型
declare     v_emp_record employees%rowtype;     v_emp_id number(10);begin     v_emp_id  := 100;     select * into v_emp_record     from employees     where employee_id = v_emp_id;     dbms_output.put_line(v_emp_record.salary||' , '||v_emp_record.last_name);--用表中的列名字即可end; 
三、流程式控制制:
條件判斷:(兩種)
方式一:if ..then elseif then...else...end if;
方式二:case...when...then ..end;
迴圈結構:(三種)
方式一:loop...exit when ...end loop;
方式二:while..loop...end;
方式三:for i in ..loop ..end loop;
關鍵字:goto (類似java中的break後接一個標籤,跳出那個迴圈)、 exit
條件判斷:
--查詢出 150號 員工的工資, 若其工資大於或等於 10000 則列印 'salary >= 10000'; 
--若在 5000 到 10000 之間, 則列印 '5000<= salary < 10000'; 否則列印 'salary < 5000'
方式一
declare     v_sal employees.salary%type;     v_result varchar2(20);begin     select salary into  v_sal from employees where employee_id = 150;     if v_sal >= 10000 then v_result := 'salary >= 10000';     elsif v_sal >=5000 then v_result := 'salary >= 5000';     else v_result := 'salary < 5000';     end if;     dbms_output.put_line(v_sal||' , '||v_result);end;
方式二
declare     v_sal employees.salary%type;     v_result varchar2(20);begin     select salary into  v_sal from employees where employee_id = 150;     v_result :=     case trunc(v_sal/5000) when 2  then 'salary >= 10000'                            when 1  then '5000 <= salary < 10000'                            when 0  then 'salary < 5000'     end;     dbms_output.put_line(v_sal||' , '||v_result);end;
case...when..then..相當於java的switch,使用起來有局限性,還是if..then..elsif...then比較好
注意,if..then每一次後面都要加“分號”,而case..when..then不能加,分號的問題在PL/DQL中比較坑
迴圈結構:
--使用迴圈語句列印 1 - 100.(三種方式)
--(1)初始化 (2)迴圈體 (3)迴圈條件 (4)迭代條件
declare       --(1)       v_i number(3) := 1;/*方式一begin       loop       --(2)           dbms_output.put_line(v_i);           --(4)          v_i := v_i + 1;       --(3)       exit when v_i >100;       end  loop;--注意每一行,都要有“分號”end;*/方式二:(推薦使用 )begin       while v_i <= 100 loop             dbms_output.put_line(v_i);             v_i := v_i + 1;        end loop;end;/*方式三begin        for i in 1..100 loop --for i in reverse 1..100 loop,這樣就是反著,從100-1,還要注意in後面是兩個“.”            dbms_output.put_line(i);        end loop;end;*/
輸出1-100的所有質數
declare  v_i number(3) := 2;  v_j number(3) := 2;  v_flag number(3) := 1;begin  /*while v_i<=100 loop          while v_j <= sqrt(v_i) loop              if mod(v_i,v_j)=0 then v_flag := 0;              goto OK;              end if;          v_j := v_j + 1;              end loop;  <<OK>>  if v_flag = 1 then dbms_output.put_line(v_i);  end if;  v_j := 2;  v_i := v_i + 1;  v_flag := 1;  end loop;  */  for i in 2..100 loop      for j in 2..sqrt(i) loop          if mod(i,j)=0 then v_flag := 0;          goto OK;          end if;      end loop;      <<OK>>                  if v_flag = 1 then dbms_output.put_line(i);      end if;      v_flag := 1;  end loop;      end;
對於while 迴圈的嵌套。特別要注意初始化條件

四、遊標的使用(類似於java的iterator)
主要方便用於處理多行資料。
declare  --定義一個記錄類型  type v_record is record(       v_sal employees.salary%type,       v_last_name employees.last_name%type  );  --聲明一個記錄類型  v_emp_record v_record;  --定義一個遊標  cursor emp_sal_cursor is select salary,last_name from employees where department_id = 80;begin  --開啟遊標  open emp_sal_cursor;  --提取遊標  fetch emp_sal_cursor into v_emp_record;  while emp_sal_cursor%found loop        dbms_output.put_line(v_emp_record.v_last_name||' : '||v_emp_record.v_sal);        fetch emp_sal_cursor into v_emp_record;  end loop;  close emp_sal_cursor;end;
遊標的使用,用for比較簡單
declare  cursor emp_sal_cursor is select salary,last_name from employees where department_id = 80;begin  for c in emp_sal_cursor loop       dbms_output.put_line(c.last_name||c.salary);      end loop;end;
帶參數的遊標
declare    --定義遊標    cursor emp_sal_cursor(dept_id number, sal number) is            select salary + 1000 sal, employee_id id            from employees            where department_id = dept_id and salary > sal;        --定義基數變數    temp number(4, 2);begin    --處理遊標的迴圈操作    for c in emp_sal_cursor(sal => 4000, dept_id => 80) loop          --判斷員工的工資, 執行 update 操作          --dbms_output.put_line(c.id || ': ' || c.sal);                    if c.sal <= 5000 then             temp := 0.05;          elsif c.sal <= 10000 then             temp := 0.03;             elsif c.sal <= 15000 then             temp := 0.02;          else             temp := 0.01;          end if;                    dbms_output.put_line(c.sal || ': ' || c.id || ', ' || temp);          --update employees set salary = salary * (1 + temp) where employee_id = c.id;    end loop;end;
隱式遊標
隱式遊標屬性
SQL%FOUND 布爾型屬性,當最近一次讀記錄時成功返回,則值為 TRUE;
SQL%NOTFOUND 布爾型屬性,與%FOUND 相反;
SQL %ROWCOUNT 數字型屬性, 返回已從遊標中讀取得記錄數;
SQL %ISOPEN 布爾型屬性, 取值總是 FALSE。SQL 命令執行完畢立即關閉隱式遊標。
--更新指定員工資訊,如果該員工沒有找到,則列印”查無此人”資訊。
declare   v_sal employees.salary%type;  v_empid employees.employee_id%type := 101;begin  update employees  set last_name = 'ABC'  where employee_id = v_empid;  if sql%notfound then --     dbms_output.put_line('查無此人');  end if;end;
五、異常處理(三種類型)
異常處理概念
  異常情況處理(EXCEPTION) 是用來處理正常執行過程中未預料的事件, 程式塊的異常處理預定義的錯誤
和 自訂錯誤, 由於 PL/SQL  程式塊一旦產 生異常而沒有指出如何處理時,程式就會自動終止整個程式運行
共有三種類型:
1.預定義 ( Predefined ) 錯誤
ORACLE 預定義的異常情況大約有 24 個。對這種異常情況的處理,無需在程式中定義,由 由 ORACLE  自動
將其引發。
2.非預定義 ( Predefined )錯誤
即其他標準的 ORACLE 錯誤。對這種異常情況的處理,需要使用者在程式中定義,然後由 ORACLE 自動將
其引發。
3.使用者定義(User_define) 錯誤
程式執行過程中,出現編程人員認為的非正常情況。對這種異常情況的處理, 需要 使用者在程式中定義,
然後顯式地在程式中將其引發。
異常處理的基本結構:
EXCEPTIONWHEN first_exception THEN <code to handle first exception >WHEN second_exception THEN <code to handle second exception >WHEN OTHERS THEN <code to handle others exception >END;
異常處理可以按任意次序排列,但 OTHERS 必須放在最後.
預定義異常
declare  v_sal employees.salary%type;begin  select salary into v_sal from employees  where employee_id > 100;  dbms_output.put_line(v_sal);exception  when too_many_rows then dbms_output.put_line('要輸出的行數太多了!');  when others then dbms_output.put_line('其他錯誤!');end;
非預定義異常
步驟如下:
1.在 PL/SQL  塊的定義部分定義異常情況:
<異常情況> EXCEPTION;
2.  將其定義好的異常情況,與標準的 ORACLE  錯誤聯絡起來,使用 PRAGMA EXCEPTION_INIT  語句:
PRAGMA EXCEPTION_INIT(< 異常情況>, < 錯誤碼>);
3. 在 PL/SQL  塊的異常情況處理部分對異常情況做出相應的處理。
SQL>delete employeeswhere employee_id = 100ORA-02292: 違反完整約束條件 (SCOTT.DEPT_MGR_FK) - 已找到子記錄因為自己表裡有manager_id也指向自己表裡的employee_id,而刪除emp_id,因為manager_id指向,所以或無法刪除declare  e_deleteid_exception exception;  pragma exception_init(e_deleteid_exception,-2292);--將2292這個錯和自己定義的異常名稱關聯起來begin  delete employees  where employee_id = 100;exception  when e_deleteid_exception then dbms_output.put_line('違反完整性條件約束異常!');end;

使用者自訂的異常處理

當與一個異常錯誤相關的錯誤出現時,就會隱含觸發該異常錯誤。 使用者定義的異常錯誤是通過顯式使
用 RAISE  語句來觸發。當引發一個異常錯誤時,控制就轉向到 EXCEPTION  塊異常錯誤部分,執行錯誤處
理代碼。
步驟如下:
1. 在 在 PL/SQL  塊的定義部分定義異常情況:
< 異常情況> EXCEPTION;
2. RAISE < 異常情況>;
3.在 PL/SQL  塊的異常情況處理部分對異常情況做出相應的處理
在非預言定義異常的基礎上
declare  e_deleteid_exception exception;  pragma exception_init(e_deleteid_exception,-2292);  e_too_high_sal_exception exception; --自訂異常  v_sal employees.salary % type;begin   delete from employees where employee_id = 100;  select salary into v_sal from employees where employee_id = 100;  if v_sal > 10000 then   raise e_too_high_sal_exception;   --拋出異常  end if;exception  when e_too_high_sal_exception then dbms_output.put_line('工資太高了');  when e_deleteid_exception then dbms_output.put_line('違反完整性條件約束異常');  when others then dbms_output.put_line('其他異常');end;
1-5為基礎中的基礎
六、儲存函數和預存程序

過程和函數的唯一區別是函數總向調用者返回資料,而過程則不返回資料。
即儲存函數(有返回值)、預存程序(無返回值)
-----儲存函數:
建立函數1.  建立內嵌函數文法如下:CREATE [OR REPLACE] FUNCTION function_name[ (argment [ { IN | IN OUT }] Type,argment [ { IN | OUT | IN OUT } ] Type ][ AUTHID DEFINER | CURRENT_USER ]RETURN return_type{ IS | AS }<類型.變數的說明>BEGINFUNCTION_bodyEXCEPTION其它語句END;
說明:
1) OR REPLACE 為可選. 有了它, 可以或者建立一個新函數或者替換相同名字的函數, 而不會出現衝突
2) 函數名後面是一個可選的參數列表, 其中包含 IN, OUT 或 IN OUT 標記. 參數之間用逗號隔開. IN  參數
標記表示傳遞給函數的值在該函數執行中不改變; OUT  標記表示一個值在函數中進行計算並通過該參
數傳遞 給調用語句; IN OUT  標記表示傳遞給函數的值可以變化並傳遞給調用語句.  若省略標記,  則參數
隱含為 IN 。
3) 因為函數需要返回一個值, 所以 RETURN 包含返回結果的資料類型。
--儲存函數結構
create or replase function func_name (depart_id number, salary number)return number --返回某部門所有的工資is            --函數在使用過程中,需要聲明的變數、記錄類型record、遊標cursorbegin       --函數的執行體exception       --處理函數執行過程中的異常end;
Hello,World示範
create or replace function HelloDemoreturn varchar2isbegin       return 'Hello,World';end;
顯示Function created,說明函數已經建立
調用函數
方式一:
begin  dbms_output.put_line(HelloDemo);end;
方式二:
SQL>select HelloDemo from dual; /*create or replace function HelloDemo(v_world varchar2)return varchar2isbegin       return 'Hello'||v_world;end;*//*select HelloDemo('Worrld') from dual*/
擷取系統時間函數
create or replace function get_sysdatereturn dateis   v_date date;begin       v_date := sysdate;       return v_date;end;select get_date from  dual;

定義兩個數相加的函數

create or replace function add_func(v_num1 number,v_num2 number)return numberis   v_sum number(10);--這裡需要指定長度begin       v_sum := v_num1 + v_num2;       return v_sum;end;select add_func(1,2) from dual;

擷取指定部門的工資總和

create or replace function get_all_sal(dept_id number)return numberis   v_sumsal number(20,2) := 0;      cursor salary_cursor is select salary from employees where department_id = dept_id;begin       for c in salary_cursor loop       v_sumsal := v_sumsal + c.salary;       end loop;              return v_sumsal;end;
關於OUT形的參數
因為函數只能有一個返回值,PL/SQL程式可以通過OUT參數實現多個返回值

擷取指定部門的工資總和,人員總和
create or replace function get_all_sal(dept_id number,emp_num out number)--注意out這裡return numberis   v_sumsal number(20,2) := 0;      cursor salary_cursor is select salary from employees where department_id = dept_id;begin          emp_num := 0;       for c in salary_cursor loop       v_sumsal := v_sumsal + c.salary;       emp_num := emp_num + 1;       end loop;              return v_sumsal;end;輸出declare  v_num number(3):=0;begin  dbms_output.put_line(get_all_sal(80,v_num));     dbms_output.put_line(v_num); --v_num就是部門人數end;    
-----預存程序:
--定義預存程序,實現指定部門的工資(通過out參數),要求部門id和工資總數為參數
create or replace procedure get_sal(dept_id number,v_sal out number)--不需要傳回值is   cursor salary_cursor is select salary from employees where department_id = dept_id;begin          v_sal := 0;       for c in salary_cursor loop       v_sal := v_sal + c.salary;       end loop;       dbms_output.put_line(v_sal);end;
declare  v_sal number(10):=0;begin  get_sal(80,v_sal); --直接調用即可end;
因為預存程序不需要返回值,所以可以把增刪改的操作定義預存程序
七、觸發器
觸發器是許多關聯式資料庫系統都提供的一項技術。在 ORACLE 系統裡, 觸發器類似過程和函數,都有
聲明,執行和異常處理過程的 PL/SQL
一個helloworld層級的觸發器
create or replace trigger hello_triggerafter update on employees--for each rowbegin     dbms_output.put_line('hello...');    --dbms_output.put_line('old.salary:'|| :OLD.salary||',new.salary'||:NEW.salary);end;
然後執行:update employees set salary = salary + 1000;

6-7重點


相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.