Oracle速查語法:PL/SQL

目錄

.

PL/SQL 結構

DECLARE        --聲明部分
        聲明語句
BEGIN         --執行部分
        執行語句

EXCEPTION         --異常處理部分
        執行語句

END;

變量聲明

<變量名> 類型[:=初始值];
特殊類型 字段%type
示例: name emp.ename%type –表示name的類型和emp.ename的類型相同
表 %rowtype
示例:
test emp%rowtype –表示test的類型爲emp表的行類型;也有 .empno; .ename; .sal ;等屬性


常量聲明

<變量名> CONSTANT 類型:=初始值; 示例: pi constant number(5,3):=3.14;


全局變量聲明
VARIABLE <變量名> 類型;
示例: VARIABLE num number;


使用全局變量
:<變量名>
示例:
:num:=100;
i=:num;


查看全局變量的值
print <變量名>
示例: print num;


賦值運算符: :=
示例: num := 100;


使用SELECT <列名> INTO <變量名> FROM <表名> WHERE <條件>
注意select into 語句的返回結果只能爲一行;
示例:test emp%rowtype;
select * into test from emp where empno=7788;


用戶交互輸入
<變量>:=’&變量’
示例:
num:=#


注意oracle的用戶交互輸入是先接受用戶輸入的所有值後在執行語句;
所以不能使用循環進行用戶交互輸入;

條件控制語句
IF <條件1> THEN
    語句
[ELSIF <條件2> THEN
   語句
          .
          .
          .
ELSIF <條件n> THEN
   語句]
[ELSE 
    語句]
END IF;

循環控制語句

1.LOOP

LOOP
   語句;
   EXIT WHEN <條件>
END LOOP;

2.WHILE LOOP

WHILE <條件>
LOOP
   語句;
END LOOP;

3.FOR

FOR <循環變量> IN 下限..上限
LOOP
   語句;
END LOOP;
NULL 語句
null;
表示沒有操作;

註釋使用
單行註釋: –
多行註釋:/* …….
……………*/

異常處理

EXCEPTION 
   WHEN <異常類型> THEN
            語句;
   WHEN OTHERS THEN
            語句;
END;

.

顯示遊標

定義:

CURSOR <遊標名> IS <SELECT 語句> [FOR UPDATE | FOR UPDATE OF 字段];

[FOR UPDATE | FOR UPDATE OF 字段] –給遊標加鎖,既是在程序中有”UPDATE”,”INSERT”,”DELETE”語句對數據庫操作時。

遊標自動給指定的表或者字段加鎖,防止同時有別的程序對指定的表或字段進行”UPDATE”,”INSERT”,”DELETE”操作.

在使用”DELETE”,”UPDATE”後還可以在程序中使用CURRENT OF <遊標名> 子句引用當前行.

操作:

OPEN <遊標名> --打開遊標
    FETCH <遊標名> INTO 變量1,變量2,變量3,....變量n,;
                或者
    FETCH <遊標名> INTO 行對象;         --取出遊標當前位置的值 
    CLOSE <遊標名> --關閉遊標
屬性: %NOTFOUND --如果FETCH語句失敗,則該屬性爲"TRUE",否則爲"FALSE";
    %FOUND --如果FETCH語句成果,則該屬性爲"TRUE",否則爲"FALSE";
    %ROWCOUNT --返回遊標當前行的行數;
    %ISOPEN --如果遊標是開的則返回"TRUE",否則爲"FALSE";

使用:

LOOP循環
   示例:
DECLARE 
     cursor c_1 is select * from emp;     --定義遊標
     r c_1%rowtype;      --定義一個行對象,用於獲得遊標的值
BEGIN
     if c_1%isopen then
          CLOSE c_1;
     end if;               
     OPEN c_1;          --判斷遊標是否打開.如果開了將其關閉,然後在打開
     dbms_output.put_line('行號 姓名 薪水');
     LOOP
     FETCH c_1 INTO r;     --取值
     EXIT WHEN c_1%NOTFOUND;     --如果遊標沒有取到值,退出循環.
     dbms_output.put_line(c_1%rowcount||' '||r.ename||' '||r.sal);    --輸出結果,需要 set serverout on 才能顯示.
     END LOOP;
END;

FOR循環

示例:

DECLARE 
     cursor c_1 is select ename,sal from emp;     --定義遊標     
BEGIN
     dbms_output.put_line('行號 姓名 薪水');
     FOR i IN c_1         --for循環中的循環變量i爲c_1%rowtype類型;
     LOOP
     dbms_output.put_line(c_1%rowcount||' '||i.ename||' '||i.sal);    --輸出結果,需要 set serverout on 才能顯示.
     END LOOP;
END; 

for循環使用遊標是在循環開始前自動打開遊標,並且自動取值到循環結束後,自動關閉遊標.

遊標加鎖示例:

DECLARE 
     cursor c_1 is select ename,sal from emp for update of sal;     --定義遊標對emp表的sal字段加鎖.     
BEGIN
     dbms_output.put_line('行號 姓名 薪水');
     FOR i IN c_1         --for循環中的循環變量i爲c_1%rowtype類型;
     LOOP
     UPDATE EMP set sal=sal+100 WHERE CURRENT OF c_1; --表示對當前行的sal進行跟新.
     END LOOP;
     FOR i IN c_1        
     LOOP
     dbms_output.put_line(c_1%rowcount||' '||i.ename||' '||i.sal);    --輸出結果,需要 set serverout on 才能顯示.
     END LOOP;
END; 

代參數的遊標

定義:

CURSOR <遊標名>(參數列表) IS

DECLARE 
     cursor c_1(name emp.ename%type) is select ename,sal from emp where ename=name;     --定義遊標     
BEGIN
     dbms_output.put_line('行號 姓名 薪水');
     FOR i IN c_1('&name')         --for循環中的循環變量i爲c_1%rowtype類型;
     LOOP
     dbms_output.put_line(c_1%rowcount||' '||i.ename||' '||i.sal);    --輸出結果,需要 set serverout on 才能顯示.
     END LOOP;
END; 

隱試遊標

隱試遊標遊標是系統自動生成的。每執行一個DML語句就會產生一個隱試遊標,起名字爲SQL;

隱試遊標不能進行”OPEN” ,”CLOSE”,”FETCH”這些操作;

屬性:

    %NOTFOUND --如果DML語句沒有影響到任何一行時,則該屬性爲"TRUE",否則爲"FALSE";
    %FOUND --如果DML語句影響到一行或一行以上時,則該屬性爲"TRUE",否則爲"FALSE";
    %ROWCOUNT --返回遊標當最後一行的行數;

個人認爲隱試遊標的作用是判斷一個DML語句;

示例:

BEGIN
    DELETE FROM EMP WHERE empno=&a;
    IF SQL%NOTFOUND THEN
        dbms_output.put_line('empno不存在');
    END IF;
   IF SQL%ROWCOUNT>0 THEN
        dbms_output.put_line('刪除成功');
    END IF;
END; 

a

PL/SQL表

pl/sql表只有兩列,其中第一列爲序號列爲INTEGER類型,第二列爲用戶自定義列.

定義:

TYPE <類型名> IS TABLE OF <列的類型> [NOT NULL] INDEX BY BINARY_INTEGER;

<列的類型>可以爲Oracle的數據類行以及用戶自定義類型;

屬性方法:

.count --返回pl/sql表的總行數
.delect --刪除pl/sql表的所有內容
.delect(行數) --刪除pl/sql表的指定的行
.delct(開始行,結束行) --刪除pl/sql表的多行
.first --返回表的第一個INDEX;
.next(行數) --這個行數的下一條的INDEX;
.last --返回表的最後一個INDEX;

使用

示例:

DECLARE
     TYPE mytable IS TABLE OF VARCHAR2(20) index by binary_integer; --定義一個名爲mytable的PL/sql表類型;
     cursor c_1 is select ename from emp; 
     n number:=1;
     tab_1 mytable; --爲mytable類型實例化一個tab_1對象;
BEGIN
     for i in c_1
     loop
          tab_1(n):=i.ename; --將得到的值輸入pl/sql表
          n:=n+1; 
    end loop;
     n:=1;
     tab_1.delete(&要刪除的行數); --刪除pl/sql表的指定行
     for i in tab_1.first..tab_1.count
     loop
          dbms_output.put_line(n||' '||tab_1(n)); --打印pl/sql表的內容
          n:=tab_1.next(n);
     end loop;
EXCEPTION 
     WHEN NO_DATA_FOUND THEN                    --由於刪除了一行,會發生異常,下面語句可以接着刪除的行後顯示
          for i in n..tab_1.count+1
     loop
          dbms_output.put_line(n||' '||tab_1(n));
          n:=tab_1.next(n);
     end loop; 
END; 

.

PL/SQL記錄

pl/sql表只有一行,但是有多列。

定義:

TYPE <類型名> IS RECORD <列名1 類型1,列名2 類型2,...列名n 類型n,> [NOT NULL]

<列的類型>可以爲Oracle的數據類行以及用戶自定義類型;可以是記錄類型的嵌套

使用

示例:

DECLARE
     TYPE myrecord IS RECORD(id emp.empno%type,
     name emp.ename%type,sal emp.sal%type);     --定義一個名爲myrecoed的PL/sql記錄類型;
     rec_1 myrecord; --爲myrecord類型實例化一個rec_1對象;
BEGIN
          select empno,ename,sal into rec_1.id,rec_1.name,rec_1.sal
          from emp where empno=7788;        --將得到的值輸入pl/sql記錄
          dbms_output.put_line(rec_1.id||' '||rec_1.name||' '||rec_1.sal); --打印pl/sql記錄的內容
END; 

結合使用PL/SQL表和PL/SQL記錄

示例:

DECLARE
     CURSOR c_1 is select empno,ename,job,sal from emp;
     TYPE myrecord IS RECORD(empno emp.empno%type,ename emp.ename%type,
job emp.job%type,sal emp.sal%type);     --定義一個名爲myrecoed的PL/sql記錄類型;
     TYPE mytable IS TABLE OF myrecord index by binary_integer; 
                                                                   --定義一個名爲mytable的PL/sql表類型;字段類型爲PL/sql記錄類型;

     n number:=1;
     tab_1 mytable; --爲mytable類型實例化一個tab_1對象;
BEGIN
          --賦值
          for i in c_1
          loop
               tab_1(n).empno:=i.empno;
               tab_1(n).ename:=i.ename;                     
               tab_1(n).job:=i.job;
               tab_1(n).sal:=i.sal;
               n:=n+1;
          end loop;
          n:=1;
          --輸出
          for i in n..tab_1.count
          loop
                dbms_output.put_line(i||' '||tab_1(i).empno
                ||' '||tab_1(i).ename||' '||tab_1(i).job||' '||tab_1(i).sal);
          end loop;
END; 

.

強型REF遊標

定義:TYPE <遊標名> IS REF CURSOR RETURN<返回類型>;

操作:

OPEN <遊標名> For <select 語句> --打開遊標
    FETCH <遊標名> INTO 變量1,變量2,變量3,....變量n,;
                或者
    FETCH <遊標名> INTO 行對象;         --取出遊標當前位置的值 
    CLOSE <遊標名> --關閉遊標
屬性: %NOTFOUND --如果FETCH語句失敗,則該屬性爲"TRUE",否則爲"FALSE";
    %FOUND --如果FETCH語句成果,則該屬性爲"TRUE",否則爲"FALSE";
    %ROWCOUNT --返回遊標當前行的行數;
    %ISOPEN --如果遊標是開的則返回"TRUE",否則爲"FALSE";

使用:

示例:

DECLARE 
     type c_type is ref cursor return emp%rowtype;     --定義遊標
     c_1 c_type;      --實例化這個遊標類型
     r emp%rowtype;
BEGIN
     dbms_output.put_line('行號 姓名 薪水');
     open c_1 for select * from emp;
     loop 
     fetch c_1 into r;
     exit when c_1%notfound;
     dbms_output.put_line(c_1%rowcount||' '||r.ename||' '||r.sal);    --輸出結果,需要 set serverout on 才能顯示.
     END LOOP;
close c_1;
END;

弱型REF遊標

定義:TYPE <遊標名> IS REF CURSOR;

OPEN <遊標名> For <select 語句> --打開遊標
    FETCH <遊標名> INTO 變量1,變量2,變量3,....變量n,;
                或者
    FETCH <遊標名> INTO 行對象;         --取出遊標當前位置的值 
    CLOSE <遊標名> --關閉遊標
屬性: %NOTFOUND --如果FETCH語句失敗,則該屬性爲"TRUE",否則爲"FALSE";
    %FOUND --如果FETCH語句成果,則該屬性爲"TRUE",否則爲"FALSE";
    %ROWCOUNT --返回遊標當前行的行數;
    %ISOPEN --如果遊標是開的則返回"TRUE",否則爲"FALSE";

示例:

set autoprint on;
var c_1 refcursor;
DECLARE
   n number;
BEGIN
   n:=&請輸入;
   if n=1 then
         open :c_1 for select * from emp;
   else 
         open :c_1 for select * from dept;
   end if;
END; 

.

過程

定義:CREATE [OR REPLACE] PROCEDURE <過程名>[(參數列表)] IS
[局部變量聲明]
BEGIN
可執行語句
EXCEPTION
異常處理語句
END [<過程名>];


變量的類型:in 爲默認類型,表示輸入; out 表示只輸出;in out 表示即輸入又輸出;


操作以有的過程:在PL/SQL塊中直接使用過程名;在程序外使用execute <過程名>[(參數列表)]

使用:

示例:
創建過程:

create or replace procedure p_1(n in out number) is
    r emp%rowtype;
BEGIN
     dbms_output.put_line('姓名 薪水');
     select * into r from emp where empno=n;
     dbms_output.put_line(r.ename||' '||r.sal);    --輸出結果,需要 set serverout on 才能顯示.
    n:=r.sal; 
END;
使用過程:
declare
    n number;
begin
    n:=&請輸入員工號;
    p_1(n);
    dbms_output.put_line('n的值爲 '||n);
end; 

刪除過程:
DROP PROCEDURE <過程名>;

.

函數

定義:CREATE [OR REPLACE] FUNCTION <過程名>[(參數列表)] RETURN 數據類型 IS
[局部變量聲明]
BEGIN
可執行語句
EXCEPTION
異常處理語句
END [<過程名>];


變量的類型:in 爲默認類型,表示輸入; out 表示只輸出;in out 表示即輸入又輸出;

使用:

示例:
創建函數:

create or replace function f_1(n number) return number is
    r emp%rowtype;
BEGIN
     dbms_output.put_line('姓名 薪水');
     select * into r from emp where empno=n;
     dbms_output.put_line(r.ename||' '||r.sal);    --輸出結果,需要 set serverout on 才能顯示.
     return r.sal;
END;
使用函數:
declare
    n number;
     m number;
begin
    n:=&請輸入員工號;
    m:=f_1(n);
    dbms_output.put_line('m的值爲 '||m);
end; 

刪除函數:
DROP FUNCTION <函數名>;


.

數據包

定義: 定義包的規範
CREATE [OR REPLACE] PACKAGE <數據包名> AS
–公共類型和對象聲明
–子程序說明
END;
定義包的主體
CREATE [OR REPLACE] PACKAGE BODY <數據包名> AS
–公共類型和對象聲明
–子程序主體
BEGIN
-初始化語句
END;

使用:

示例:
創建數據包規範:

create or replace package pack_1 as
      n number;
      procedure p_1;
      FUNCTION f_1 RETURN number;
end;

創建數據包主體:

create or replace package body pack_1 as
  procedure p_1 is 
       r emp%rowtype;
  begin 
       select * into r from emp where empno=7788;
       dbms_output.put_line(r.empno||' '||r.ename||' '||r.sal);
   end;

   FUNCTION f_1 RETURN number is
       r emp%rowtype;
   begin
        select * into r from emp where empno=7788;
       return r.sal;
   end;
end;

使用包:

declare 
      n number;
begin
      n:=&請輸入員工號;
      pack_1.n:=n;
      pack_1.p_1;
      n:=pack_1.f_1;
      dbms_output.put_line('薪水爲 '||n);
end;

在包中使用REF遊標
示例:
創建數據包規範:

create or replace package pack_2 as
     TYPE c_type is REF CURSOR; --建立一個ref遊標類型
     PROCEDURE p_1(c1 in out c_type); --過程的參數爲ref遊標類型;
end;

創建數據包主體:

create or replace package body pack_2 as
  PROCEDURE p_1(c1 in out c_type) is 
  begin 
       open c1 for select * from emp;
   end;
end;

使用包:

var c_1 refcursor;
set autoprint on;
execute pack_2.p_1(:c_1);

刪除包:
DROP PACKAGE <包名>;


.

觸發器


創建觸發器:

    CREATE [OR REPLACE] TRIGGER <觸發器名>
    BEFORE|AFTER
    INSERT|DELETE|UPDATE [OF <列名>] ON <表名>
    [FOR EACH ROW]
     WHEN (<條件>)
     <pl/sql塊>
 關鍵字"BEFORE"在操作完成前觸發;"AFTER"則是在操作完成後觸發;
 關鍵字"FOR EACH ROW"指定觸發器每行觸發一次.
  關鍵字"OF <列名>" 不寫表示對整個表的所有列.
 WHEN (<條件>)表達式的值必須爲"TRUE".

特殊變量:
:new –爲一個引用最新的列值;
:old –爲一個引用以前的列值; 這些變量只有在使用了關鍵字 “FOR EACH ROW”時才存在.且update語句兩個都有,而insert只有:new ,delect 只有:old;


使用RAISE_APPLICATION_ERROR
語法:RAISE_APPLICATION_ERROR(錯誤號(-20000到-20999),消息[,{true|false}]);
拋出用戶自定義錯誤.
如果參數爲’TRUE’,則錯誤放在先前的堆棧上.


INSTEAD OF 觸發器
INSTEAD OF 觸發器主要針對視圖(VIEW)將觸發的dml語句替換成爲觸發器中的執行語句,而不執行dml語句.

禁用某個觸發器
ALTER TRIGGER <觸發器名> DISABLE
重新啓用觸發器
ALTER TRIGGER <觸發器名> ENABLE
禁用所有觸發器
ALTER TRIGGER <觸發器名> DISABLE ALL TRIGGERS
啓用所有觸發器
ALTER TRIGGER <觸發器名> ENABLE ALL TRIGGERS
刪除觸發器
DROP TRIGGER <觸發器名>

.

自定義對象

創建對象:
CREATE [OR REPLACE] TYPE <對象名> AS OBJECT(
屬性1 類型
屬性2 類型


方法1的規範(MEMBER PROCEDURE <過程名>
方法2的規範 (MEMBER FUNCTION <函數名> RETURN 類型)
      .

PRAGMA RESTRIC_REFERENCES(<方法名>,WNDS/RNDS/WNPS/RNPS);
關鍵字”PRAGMA RESTRIC_REFERENCES”通知ORACLE函數按以下模式之一操作;
WNDS-不能寫入數據庫狀態;
RNDS-不能讀出數據庫狀態;
WNPS-不能寫入包狀態;
RNDS-不能讀出包狀態;

創建對象主體:
  CREATE [OR REPLACE] TYPE body <對象名> AS 
  方法1的規範(MEMBER PROCEDURE <過程名> is   <PL/SQL塊>
  方法2的規範 (MEMBER FUNCTION <函數名> RETURN 類型 is <PL/SQL塊>  
 END;

使用MAP方法和ORDER方法

用於對自定義類型排序。每個類型只有一個MAP或ORDER方法。
 格式:MAP MEMBER FUNCTION <函數名> RETURN 類型 
        ORDER MEMBER FUNCTION <函數名> RETURN NUMBER

創建對象表

CREATE TABLE <表名> OF <對象類型>

示例:

  1. 創建name 類型
     create or replace type name_type as object(
          f_name varchar2(20),
          l_name varchar2(20),
          map member function name_map return varchar2); 

     create or replace type body name_type as
          map member function name_map return varchar2 is --對f_name和l_name排序
          begin 
               return f_name||l_name;
          end;
          end;

2 創建address 類型

     create or replace type address_type as object
       ( city varchar2(20),
           street varchar2(20),
           zip number,
      order member function address_order(other address_type) return number);

      create or replace type body address_type as
      order member function address_order(other address_type) return number is --對zip排序
      begin
           return self.zip-other.zip;
      end;
      end;

3 創建stu對象

       create or replace type stu_type as object (
       stu_id number(5),
       stu_name name_type,
       stu_addr address_type,
       age number(3),
       birth date, 
       map member function stu_map return number,
      member procedure update_age);

      create or replace type body stu_type as
       map member function stu_map return number is --對stu_id排序
       begin
             return stu_id;
       end;
      member procedure update_age is --求年齡用現在時間-birth
       begin 
             update student set age=to_char(sysdate,'yyyy')-to_char(birth,'yyyy') where stu_id=self.stu_id;
       end; 
       end; 
  1. 創建對象表
    `create table student of stu_type(primary key(stu_id));`

5.向對象表插值

      insert into student values(1,name_type('關','羽'),address_type('武漢','成都路',43000), null,sysdate-365*20);

6.使用對象的方法

     delcare
          aa stu_type;
     begin
          select value(s) into aa from student s where stu_id=1; --value()將對象表的每一行轉成行對象括號中必須爲表的別名
          aa.update_age();
     end; 

7.select stu_id,s.stu_name.f_name,s.stu_name.l_name from student s; –查看類型的值

8.select ref(s) from student s ; –ref()求出行對象的OID,括號中必須爲表的別名;deref()將oid變成行隊像;

.

其他

1.在PL/SQL中使用DDL

 將sql語句賦給一個varchar2變量,在用execute immediate 這個varchar2變量即可;
 示例:
     declare
          str varchar2(200);
     begin 
          str:='create table test(id number,name varchar2(20))'; --創建表
          execute immediate str;   
          str:='insert into test values(3,''c'')'; --向表裏插數據
          execute immediate str; 
     end;    

但是要隊這個表插入數據也必須使用execute immediate 字符變量

2.判斷表是否存在;
示例:

     declare
          n tab.tname%type;
     begin
          select tname into n from tab where tname='&請輸入表名';
          dbms_output.put_line('此表以存在');
     exception
          when no_data_found then
          dbms_output.put_line('還沒有此表');
     end; 

2.查看以有的過程;
示例:

select object_name,object_type,status from user_objects where object_type='PROCEDURE';

結束

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章