PL/SQL程式由三個塊組成,即聲明部分、執行部分、異常處理部分。
PL/SQL塊的結構如下:
DECLARE
--聲明部分: 在此聲明PL/SQL用到的變量,類型及遊标,以及局部的存儲過程和函數
BEGIN
-- 執行部分: 過程及SQL 語句 , 即程式的主要部分
EXCEPTION
-- 執行異常部分: 錯誤處理
END;
其中:執行部分不能省略。
PL/SQL塊可以分為三類:
1. 無名塊或匿名塊(anonymous):動态構造,隻能執行一次,可調用其它程式,但不能被其它程式調用。
2. 命名塊(named):是帶有名稱的匿名塊,這個名稱就是标簽。
3. 子程式(subprogram):存儲在資料庫中的存儲過程、函數等。當在資料庫上建立好後可以在其它程式中調用它們。
4. 觸發器 (Trigger):當資料庫發生操作時,會觸發一些事件,進而自動執行相應的程式。
5. 程式包(package):存儲在資料庫中的一組子程式、變量定義。在包中的子程式可以被其它程式包或子程式調用。但如果聲明的是局部子程式,則隻能在定義該局部子程式的塊中調用該局部子程式。
l PL/SQL塊中可以包含子塊;
l 子塊可以位于 PL/SQL中的任何部分;
l 子塊也即PL/SQL中的一條指令;
PL/SQL程式設計中的辨別符定義與SQL 的辨別符定義的要求相同。要求和限制有:
l 辨別符名不能超過30字元;
l 第一個字元必須為字母;
l 不分大小寫;
l 不能用’-‘(減号);
l 不能是SQL保留字。
提示: 一般不要把變量名聲明與表中字段名完全一樣,如果這樣可能得到不正确的結果.
例如:下面的例子将會删除所有的紀錄,而不是’EricHu’的記錄;
DECLARE
ename varchar2(20) :='EricHu';
BEGIN
DELETE FROM scott.emp WHERE ename=ename;
END;
變量命名在PL/SQL中有特别的講究,建議在系統的設計階段就要求所有程式設計人員共同遵守一定的要求,使得整個系統的文檔在規範上達到要求。下面是建議的命名方法:
辨別符
命名規則
例子
程式變量
V_name
程式常量
C_Name
C_company_name
遊标變量
Cursor_Name
Cursor_Emp
異常辨別
E_name
E_too_many
表類型
Name_table_type
Emp_record_type
表
Name_table
Emp
記錄類型
Name_record
Emp_record
SQL*Plus 替代變量
P_name
P_sal
綁定變量
G_name
G_year_sal
在前面的介紹中,有系統的資料類型,也可以自定義資料類型。下表給出ORACLE類型和PL/SQL中的變量類型的合法使用清單:
在ORACLE8i中可以使用的變量類型有:
類型
子類
說 明
範 圍
ORACLE限制
CHAR
Character
String
Rowid
Nchar
定長字元串
民族語言字元集
0à32767
可選,确省=1
2000
VARCHAR2
Varchar, String
NVARCHAR2
可變字元串
4000
BINARY_INTEGER
帶符号整數,為整數計算優化性能
NUMBER(p,s)
Dec
Double precision
Integer
Int
Numeric
Real
Small int
小數, NUMBER 的子類型
高精度實數
整數, NUMBER 的子類型
與NUMBER等價
整數, 比 integer 小
LONG
變長字元串
0->2147483647
32,767位元組
DATE
日期型
公元前4712年1月1日至公元後4712年12月31日
BOOLEAN
布爾型
TRUE, FALSE,NULL
不使用
ROWID
存放資料庫行号
UROWID
通用行辨別符,字元類型
例1. 插入一條記錄并顯示;
Row_id ROWID;
info VARCHAR2(40);
INSERT INTO scott.dept VALUES (90, '财務室', '海口')
RETURNING rowid, dname||':'||to_char(deptno)||':'||loc
INTO row_id, info;
DBMS_OUTPUT.PUT_LINE('ROWID:'||row_id);
DBMS_OUTPUT.PUT_LINE(info);
其中:
RETURNING子句用于檢索INSERT語句中所影響的資料行數,當INSERT語句使用VALUES 子句插入資料時,RETURNING 字句還可将清單達式、ROWID和REF值傳回到輸出變量中。在使用RETURNING 子句是應注意以下幾點限制:
1.不能與DML語句和遠端對象一起使用;
2.不能檢索LONG 類型資訊;
3.當通過視圖向基表中插入資料時,隻能與單基表視圖一起使用。
例2. 修改一條記錄并顯示
info VARCHAR2(40);
UPDATE dept SET deptno=100 WHERE DNAME='财務室'
RETURNING子句用于檢索被修改行的資訊。當UPDATE語句修改單行資料時,RETURNING 子句可以檢索被修改行的ROWID和REF值,以及行中被修改列的清單達式,并可将他們存儲到PL/SQL變量或複合變量中;當UPDATE語句修改多行資料時,RETURNING 子句可以将被修改行的ROWID和REF值,以及清單達式值傳回到複合變量數組中。在UPDATE中使用RETURNING 子句的限制與INSERT語句中對RETURNING子句的限制相同。
例3. 删除一條記錄并顯示
DELETE dept WHERE DNAME='辦公室'
RETURNING子句用于檢索被删除行的資訊:當DELETE語句删除單行資料時,RETURNING 子句可以檢索被删除行的ROWID和REF值,以及被删除列的清單達式,并可将他們存儲到PL/SQL變量或複合變量中;當DELETE語句删除多行資料時,RETURNING 子句可以将被删除行的ROWID和REF值,以及清單達式值傳回到複合變量數組中。在DELETE中使用RETURNING 子句的限制與INSERT語句中對RETURNING子句的限制相同。
ORACLE 在 PL/SQL 中除了提供象前面介紹的各種類型外,還提供一種稱為複合類型的類型---記錄和表.
記錄類型類似于C語言中的結構資料類型,它把邏輯相關的、分離的、基本資料類型的變量組成一個整體存儲起來,它必須包括至少一個标量型或RECORD 資料類型的成員,稱作PL/SQL RECORD 的域(FIELD),其作用是存放互不相同但邏輯相關的資訊。在使用記錄資料類型變量時,需要先在聲明部分先定義記錄的組成、記錄的變量,然後在執行部分引用該記錄變量本身或其中的成員。
定義記錄類型文法如下:
TYPE record_name IS RECORD(
v1 data_type1 [NOT NULL] [:= default_value ],
v2 data_type2 [NOT NULL] [:= default_value ],
......
vn data_typen [NOT NULL] [:= default_value ] );
例4 :
DECLARE
TYPE test_rec IS RECORD(
Name VARCHAR2(30) NOT NULL := '胡勇',
Info VARCHAR2(100));
rec_book test_rec;
rec_book.Name :='胡勇';
rec_book.Info :='談PL/SQL程式設計;';
DBMS_OUTPUT.PUT_LINE(rec_book.Name||' ' ||rec_book.Info);
可以用 SELECT語句對記錄變量進行指派,隻要保證記錄字段與查詢結果清單中的字段相配即可。
例5 :
--定義與hr.employees表中的這幾個列相同的記錄資料類型
TYPE RECORD_TYPE_EMPLOYEES IS RECORD(
f_name hr.employees.first_name%TYPE,
h_date hr.employees.hire_date%TYPE,
j_id hr.employees.job_id%TYPE);
--聲明一個該記錄資料類型的記錄變量
v_emp_record RECORD_TYPE_EMPLOYEES;
SELECT first_name, hire_date, job_id INTO v_emp_record
FROM employees
WHERE employee_id = &emp_id;
DBMS_OUTPUT.PUT_LINE('雇員名稱:'||v_emp_record.f_name
||' 雇傭日期:'||v_emp_record.h_date
||' 崗位:'||v_emp_record.j_id);
一個記錄類型的變量隻能儲存從資料庫中查詢出的一行記錄,若查詢出了多行記錄,就會出現錯誤。
資料是具有相同資料類型的一組成員的集合。每個成員都有一個唯一的下标,它取決于成員在數組中的位置。在PL/SQL中,數組資料類型是VARRAY。
定義VARRY資料類型文法如下:
TYPE varray_name IS VARRAY(size) OF element_type [NOT NULL];
varray_name是VARRAY資料類型的名稱,size是下整數,表示可容納的成員的最大數量,每個成員的資料類型是element_type。預設成員可以取空值,否則需要使用NOT NULL加以限制。對于VARRAY資料類型來說,必須經過三個步驟,分别是:定義、聲明、初始化。
例6 :
--定義一個最多儲存5個VARCHAR(25)資料類型成員的VARRAY資料類型
TYPE reg_varray_type IS VARRAY(5) OF VARCHAR(25);
--聲明一個該VARRAY資料類型的變量
v_reg_varray REG_VARRAY_TYPE;
--用構造函數文法賦予初值
v_reg_varray := reg_varray_type
('中國', '美國', '英國', '日本', '法國');
DBMS_OUTPUT.PUT_LINE('地區名稱:'||v_reg_varray(1)||'、'
||v_reg_varray(2)||'、'
||v_reg_varray(3)||'、'
||v_reg_varray(4));
DBMS_OUTPUT.PUT_LINE('賦予初值NULL的第5個成員的值:'||v_reg_varray(5));
--用構造函數文法賦予初值後就可以這樣對成員指派
v_reg_varray(5) := '法國';
DBMS_OUTPUT.PUT_LINE('第5個成員的值:'||v_reg_varray(5));
定義一個變量,其資料類型與已經定義的某個資料變量(尤其是表的某一列)的資料類型相一緻,這時可以使用%TYPE。
使用%TYPE特性的優點在于:
l 所引用的資料庫列的資料類型可以不必知道;
l 所引用的資料庫列的資料類型可以實時改變,容易保持一緻,也不用修改PL/SQL程式。
例7:
-- 用%TYPE 類型定義與表相配的字段
TYPE T_Record IS RECORD(
T_no emp.empno%TYPE,
T_name emp.ename%TYPE,
T_sal emp.sal%TYPE );
-- 聲明接收資料的變量
v_emp T_Record;
SELECT empno, ename, sal INTO v_emp FROM emp WHERE empno=7788;
DBMS_OUTPUT.PUT_LINE
(TO_CHAR(v_emp.t_no)||' '||v_emp.t_name||' ' || TO_CHAR(v_emp.t_sal));
例8:
v_empno emp.empno%TYPE :=&no;
Type t_record is record (
v_name emp.ename%TYPE,
v_sal emp.sal%TYPE,
v_date emp.hiredate%TYPE);
Rec t_record;
SELECT ename, sal, hiredate INTO Rec FROM emp WHERE empno=v_empno;
DBMS_OUTPUT.PUT_LINE(Rec.v_name||'---'||Rec.v_sal||'--'||Rec.v_date);
PL/SQL 提供%ROWTYPE操作符, 傳回一個記錄類型, 其資料類型和資料庫表的資料結構相一緻。
使用%ROWTYPE特性的優點在于:
l 所引用的資料庫中列的個數和資料類型可以不必知道;
l 所引用的資料庫中列的個數和資料類型可以實時改變,容易保持一緻,也不用修改PL/SQL程式。
例9:
v_empno emp.empno%TYPE :=&no;
rec emp%ROWTYPE;
SELECT * INTO rec FROM emp WHERE empno=v_empno;
DBMS_OUTPUT.PUT_LINE('姓名:'||rec.ename||'工資:'||rec.sal||'工作時間:'||rec.hiredate);
ORACLE提供了LOB (Large OBject)類型,用于存儲大的資料對象的類型。ORACLE目前主要支援BFILE, BLOB, CLOB 及 NCLOB 類型。
BFILE (Movie)
存放大的二進制資料對象,這些資料檔案不放在資料庫裡,而是放在作業系統的某個目錄裡,資料庫的表裡隻存放檔案的目錄。
BLOB(Photo)
存儲大的二進制資料類型。變量存儲大的二進制對象的位置。大二進制對象的大小<=4GB。
CLOB(Book)
存儲大的字元資料類型。每個變量存儲大字元對象的位置,該位置指到大字元資料塊。大字元對象的大小<=4GB。
NCLOB
存儲大的NCHAR字元資料類型。每個變量存儲大字元對象的位置,該位置指到大字元資料塊。大字元對象的大小<=4GB。
綁定變量是在主機環境中定義的變量。在PL/SQL 程式中可以使用綁定變量作為他們将要使用的其它變量。為了在PL/SQL 環境中聲明綁定變量,使用指令VARIABLE。例如:
VARIABLE return_code NUMBER
VARIABLE return_msg VARCHAR2(20)
可以通過SQL*Plus指令中的PRINT 顯示綁定變量的值。例如:
PRINT return_code
PRINT return_msg
例10:
VARIABLE result NUMBER;
SELECT (sal*10)+nvl(comm, 0) INTO :result FROM emp
WHERE empno=7844;
--然後再執行
PRINT result
定義記錄表(或索引表)資料類型。它與記錄類型相似,但它是對記錄類型的擴充。它可以處理多行記錄,類似于進階中的二維數組,使得可以在PL/SQL中模仿資料庫中的表。
定義記錄表類型的文法如下:
TYPE table_name IS TABLE OF element_type [NOT NULL]
INDEX BY [BINARY_INTEGER | PLS_INTEGER | VARRAY2];
關鍵字INDEX BY表示建立一個主鍵索引,以便引用記錄表變量中的特定行。
方法
描述
EXISTS(n)
如果集合的第n個成員存在,則傳回true
COUNT
傳回已經配置設定了存儲空間即指派了的成員數量
FIRST
LAST
FIRST:傳回成員的最低下标值
LAST: 傳回成員的最高下标值
PRIOR(n)
傳回下标為n的成員的前一個成員的下标。如果沒有則傳回NULL
NEXT(N)
傳回下标為n的成員的後一個成員的下标。如果沒有則傳回NULL
TRIM
TRIM:删除末尾一個成員
TRIM(n) :删除末尾n個成員
DELETE
DELETE:删除所有成員
DELETE(n) :删除第n個成員
DELETE(m, n) :删除從n到m的成員
EXTEND
EXTEND:添加一個null成員
EXTEND(n):添加n個null成員
EXTEND(n,i):添加n個成員,其值與第i個成員相同
LIMIT
傳回在varray類型變量中出現的最高下标值
例11:
TYPE dept_table_type IS TABLE OF
dept%ROWTYPE INDEX BY BINARY_INTEGER;
my_dname_table dept_table_type;
v_count number(2) :=4;
FOR int IN 1 .. v_count LOOP
SELECT * INTO my_dname_table(int) FROM dept WHERE deptno=int*10;
END LOOP;
FOR int IN my_dname_table.FIRST .. my_dname_table.LAST LOOP
DBMS_OUTPUT.PUT_LINE('Department number: '||my_dname_table(int).deptno);
DBMS_OUTPUT.PUT_LINE('Department name: '|| my_dname_table(int).dname);
例12:按一維數組使用記錄表
--定義記錄表資料類型
TYPE reg_table_type IS TABLE OF varchar2(25)
INDEX BY BINARY_INTEGER;
--聲明記錄表資料類型的變量
v_reg_table REG_TABLE_TYPE;
v_reg_table(1) := 'Europe';
v_reg_table(2) := 'Americas';
v_reg_table(3) := 'Asia';
v_reg_table(4) := 'Middle East and Africa';
v_reg_table(5) := 'NULL';
DBMS_OUTPUT.PUT_LINE('地區名稱:'||v_reg_table (1)||'、'
||v_reg_table (2)||'、'
||v_reg_table (3)||'、'
||v_reg_table (4));
DBMS_OUTPUT.PUT_LINE('第5個成員的值:'||v_reg_table(5));
例13:按二維數組使用記錄表
TYPE emp_table_type IS TABLE OF employees%ROWTYPE
v_emp_table EMP_TABLE_TYPE;
SELECT first_name, hire_date, job_id INTO
v_emp_table(1).first_name,v_emp_table(1).hire_date, v_emp_table(1).job_id
FROM employees WHERE employee_id = 177;
v_emp_table(2).first_name,v_emp_table(2).hire_date, v_emp_table(2).job_id
FROM employees WHERE employee_id = 178;
DBMS_OUTPUT.PUT_LINE('177雇員名稱:'||v_emp_table(1).first_name
||' 雇傭日期:'||v_emp_table(1).hire_date
||' 崗位:'||v_emp_table(1).job_id);
DBMS_OUTPUT.PUT_LINE('178雇員名稱:'||v_emp_table(2).first_name
||' 雇傭日期:'||v_emp_table(2).hire_date
||' 崗位:'||v_emp_table(2).job_id);
運算符
意義
=
等于
<> , != , ~= , ^=
不等于
<
小于
>
大于
<=
小于或等于
>=
大于或等于
+
加号
-
減号
*
乘号
/
除号
:=
指派号
=>
關系号
..
範圍運算符
||
字元連接配接符
IS NULL
是空值
BETWEEN AND
介于兩者之間
IN
在一列值中間
AND
邏輯與
OR
邏輯或
NOT
取返,如IS NOT NULL, NOT IN
在PL/SQL程式設計中,變量指派是一個值得注意的地方,它的文法如下:
variable := expression ;
variable 是一個PL/SQL變量, expression 是一個PL/SQL 表達式.
空值加數字仍是空值:NULL + < 數字> = NULL
空值加(連接配接)字元,結果為字元:NULL || <字元串> = < 字元串>
布爾值隻有TRUE, FALSE及 NULL 三個值。如:
bDone BOOLEAN;
bDone := FALSE;
WHILE NOT bDone LOOP
Null;
資料庫指派是通過 SELECT語句來完成的,每次執行 SELECT語句就指派一次,一般要求被指派的變量與SELECT中的列名要一一對應。如:
例14:
emp_id emp.empno%TYPE :=7788;
emp_name emp.ename%TYPE;
wages emp.sal%TYPE;
SELECT ename, NVL(sal,0) + NVL(comm,0) INTO emp_name, wages
FROM emp WHERE empno = emp_id;
DBMS_OUTPUT.PUT_LINE(emp_name||'----'||to_char(wages));
提示:不能将SELECT語句中的列指派給布爾變量。
l CHAR 轉換為 NUMBER:
使用 TO_NUMBER 函數來完成字元到數字的轉換,如:
v_total := TO_NUMBER('100.0') + sal;
l NUMBER 轉換為CHAR:
使用 TO_CHAR函數可以實作數字到字元的轉換,如:
v_comm := TO_CHAR('123.45') || '元' ;
l 字元轉換為日期:
使用 TO_DATE函數可以實作 字元到日期的轉換,如:
v_date := TO_DATE('2001.07.03','yyyy.mm.dd');
l 日期轉換為字元
使用 TO_CHAR函數可以實作日期到字元的轉換,如:
v_to_day := TO_CHAR(SYSDATE, 'yyyy.mm.dd hh24:mi:ss') ;
在PL/SQL程式設計中,如果在變量的定義上沒有做到統一的話,可能會隐藏一些危險的錯誤,這樣的原因主要是變量的作用範圍所緻。變量的作用域是指變量的有效作用範圍,與其它進階語言類似,PL/SQL的變量作用範圍特點是:
l 變量的作用範圍是在你所引用的程式單元(塊、子程式、包)内。即從聲明變量開始到該塊的結束。
l 一個變量(辨別)隻能在你所引用的塊内是可見的。
l 當一個變量超出了作用範圍,PL/SQL引擎就釋放用來存放該變量的空間(因為它可能不用了)。
l 在子塊中重新定義該變量後,它的作用僅在該塊内。
例15:
Emess char(80);
DECLARE
V1 NUMBER(4);
BEGIN
SELECT empno INTO v1 FROM emp WHERE LOWER(job)='president';
DBMS_OUTPUT.PUT_LINE(V1);
EXCEPTION
When TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE ('More than one president');
END;
DECLARE
SELECT empno INTO v1 FROM emp WHERE LOWER(job)='manager';
DBMS_OUTPUT.PUT_LINE ('More than one manager');
EXCEPTION
When others THEN
Emess:=substr(SQLERRM,1,80);
DBMS_OUTPUT.PUT_LINE(emess);
在PL/SQL裡,可以使用兩種符号來寫注釋,即:
l 使用雙 ‘-‘ ( 減号) 加注釋
PL/SQL允許用 – 來寫注釋,它的作用範圍是隻能在一行有效。如:
V_Sal NUMBER(12,2); -- 人員的工資變量。
l 使用 /* */ 來加一行或多行注釋,如:
/***********************************************/
/* 檔案名: department_salary.sql */
/* 作 者: EricHu */
/* 時 間: 2011-5-9 */
提示:被解釋後存放在資料庫中的 PL/SQL 程式,一般系統自動将程式頭部的注釋去掉。隻有在 PROCEDURE 之後的注釋才被保留;另外程式中的空行也自動被去掉。
例16:
/* 檔案名: test.sql */
/* 說 明:
一個簡單的插入測試,無實際應用。*/
/* 作 者: EricHu */
/* 時 間: 2011-5-9 */
v_ename VARCHAR2(20) := 'Bill';
v_sal NUMBER(7,2) :=1234.56;
v_deptno NUMBER(2) := 10;
v_empno NUMBER(4) := 8888;
INSERT INTO emp ( empno, ename, JOB, sal, deptno , hiredate )
VALUES (v_empno, v_ename, 'Manager', v_sal, v_deptno,
TO_DATE('1954.06.09','yyyy.mm.dd') );
COMMIT;
例17:
/* 檔案名: test_deletedata.sql */
簡單的删除例子,不是實際應用。 */
VALUES ( v_empno, v_ename, ‘Manager’, v_sal, v_deptno,
TO_DATE(’1954.06.09’,’yyyy.mm.dd’) );
DECLARE
v_empno number(4) := 8888;
DELETE FROM emp WHERE empno=v_empno;
本文轉自yonghu86 51CTO部落格,原文連結:http://blog.51cto.com/yonghu/1321353,如需轉載請自行聯系原作者