變量
在定義變量時一定要為其指定一個類型,類型可以是PL/SQL類型或SQL語言的類型,一旦變量的類型確定,那么變量中所能存儲的值也就確定了,因此盡管變量的值會經常改變,但是值的類型是不可以變化的。
1.變量的聲明
語法:variable_name[CONSTANT] type [NOT NULL] [:=value];
variable_name:用於定義變量名,變量名的命名要符合標識符命名規范。
type:變量需要使用的數據類型,可以使用所有SQL類型或PL/SQL類型。
用方括號 [] 括起來的是可選部分。
CONSTANT:表示聲明為一個常量,常量在定義時需要指定初始值,一旦定義其值,不能再被改變。
NOT NULL:用於約束變量的值不能為空。
:=value :用於為變量賦初始值。
代碼1.1 變量定義示例
DECLARE
v_empname VARCHAR2(20); --定義員工名稱變量
v_deptname VARCHAR2(20); --定義部門名稱變量
v_hiredate DATE NOT NULL := SYSDATE; --定義入職日期變量
v_empno INT NOT NULL DEFAULT 1111; --變量員工編碼變量
BEGIN
NULL; --不執行任何代碼
END;
/
注: :=和DEFAULT是可以互換使用的,都用來為變量賦初始值。
一旦出現了NOT NULL關鍵字,后面必須具有賦初始值的語句。
2.變量的賦值
如果變量在聲明時沒有指定初始值,默認情況下,變量被初始化為NULL值。如果未給變量賦值,就直接使用變量,將會產生意想不到的結果。
根據變量的不同類型,可以為變量直接賦常量值,也可以使用表達式來計算變量的值。
下面的代碼根據薪資和加薪比例來計算員工的結果薪資值:
DECLARE
v_salary NUMBER(7,2);
v_rate NUMBER(7,2) :=0.12;
v_base_salary NUMBER(7,2) :=1200;
BEGIN
v_salary := v_base_salary*(1+v_rate); --使用表達式為變量賦值
DBMS_OUTPUT.put_line('員工的薪資值為:'||v_salary);
END;
在為PL/SQL變量賦值時,需要注意變量的類型。下面列出了常用的變量類型的復制方式。
DECLARE
v_string VARCHAR2(200);
v_hire_date DATE;
v_bool BOOLEAN; --PL/SQL布爾類型
BEGIN
v_bool:=True; --為布爾類型賦值
v_hire_date:=to_date('2019-04-28','yyyy-mm-dd'); --使用函數為日期賦值
v_hire_date:=SYSDATE; --使用日期函數賦值
v_hire_date:=date'2019-04-28'; --直接賦靜態日期值
v_string:='this is a string';
END;
/
通過數據庫查詢為變量賦數據庫中的值,這是進行PL/SQL編程非常常見的賦值方式,例如要從emp表中查詢員工的姓名、員工編號和雇佣日期,可以使用如下PL/SQL代碼。
DECLARE
v_empno emp.empno%TYPE; --定義變量
v_ename emp.ename%TYPE;
v_hiredate emp.hiredate%TYPE;
BEGIN
SELECT empno , ename , hiredate
INTO v_empno , v_ename , v_hiredate
FROM emp
WHERE empno = &empno;
--輸出變量的內容
DBMS_OUTPUT.put_line('員工編號:' || v_empno);
DBMS_OUTPUT.put_line('員工名稱:' || v_ename);
DBMS_OUTPUT.put_line('雇佣日期:' || v_hiredate);
END;
在定義變量類型時,使用了%TYPE來聲明與數據庫列相同的類型,然后通過SELECT-INTO語句查詢數據庫並將結果寫入變量中,可以看到INTO子句中的變量的順序要與列的順序一致。
如果SELECT-INTO查詢返回多行數據會觸發TOO_MANY_ROWS異常,如果未找到任何行數據,會觸發NO_DATA_FOUND異常。
3.使用%TYPE
使用PL/SQL的%TYPE,使得開發人員可以給予已有的變量類型,或者是數據列的類型來指定變量的類型。
DECLARE
v_empno emp.empno%TYPE; --使用%TYPE定義emp表empno列類型的變量
v_empno2 v_empno%TYPE; --定義與v_empno相同的變量
v_salary NUMBER(7,3) NOT NULL:=1350.5; --定義薪水變量
v_othersalary v_salary%TYPE:=1500; --定義與v_salary相同類型的變量
BEGIN
NULL;
END;
/
代碼中的v_empno使用%TYPE定義了與emp表中empno列相同的類型,而v_empno2定義了與v_empno相同的類型,因此
當emp表中的empno列的類型發生改變后,變量的類型會自動發生變化,並不需要手動地進行維護。
v_salary是一個具有NOT NULL約束的變量聲明,在聲明時為這個變量指定了初始值,
v_othersalary使用%TYPE定義了與v_salary相同的類型,因此也具有NOT NULL約束。
在聲明時同樣為v_othersalary指定了變量的初始值,如果不指定這個初始值,PL/SQL引擎會觸發異常。
注意:盡管v_othersalary會因為NOT NULL而觸發異常,但是emp表的empno列是不允許為空的,對於數據庫列類型,%TYPE只提供類型信息,並不提供NOT NULL約束信息,因此即便沒有為v_empno或v_empno2指定初始值,也能夠正常運行。
通過%TYPE的類型映射功能,使得在類型發生改變時非常容易對代碼進行維護,這是一種非常好的編碼風格,特別是在操作數據庫時,使用%TYPE會使得PL/SQL更加靈活。
4.使用%ROWTYPE
%ROWTYPE是與%TYPE相似的用於綁定到數據庫表列的類型,%TYPE僅綁定到單個數據庫列的類型,而%ROWTYPE則綁定到一整行的所有列類型,可以將使用%ROWTYPE定義的變量看作是一條數據類型,使用%ROWTYPE的示例代碼如下:
DECLARE
v_emp emp%ROWTYPE --定義emp表的所有列類型
BEGIN --查詢emo表並將結果寫入v_emp記錄中
SELECT *
INTO v_emp
FROM emp
WHERE empno = &empno;
--輸出結果信息
DBMS_OUTPUT.put_line(v_emp.empno || CHR(10) || v_emo.ename);
END;
代碼使用SELECT-INFO直接將一整列的數據插入使用%ROWTYPE定義的記錄類型,然后使用DBMS_OUTPUT.put_line輸出了最終的結果。
在PL/SQL中,CHR(13)表示回車,CHR(10)表示換行,通常使用CHR(13)||CHR(10)來進行回車換行。
使用%ROWTYPE定義了整行的記錄類型后,可以直接使用賦值語法為變量賦值,然后直接使用記錄類型字段值插入數據庫表。
DECLARE
v_emp emp%ROWTYPE; --定義emp表列類型的記錄
BEGIN --為記錄類型賦值
v_emp.empno:=8000;
v_emp.ename:='張三豐';
v_emp.job:='掌門';
v_empmgr:=7902;
v_emp.hiredate:=date'2019-04-28';
v_emp.sal:=8000;
v_emp.deptno:=20;
INSERT INTO emp VALUES v_emo; --將記錄類型插入數據表
END;
/
上面的代碼在使用%ROWTYPE定義了變量之后使用賦值語法為記錄中的每個列進行了賦值,最后使用INSERT INTO 語句直接將記錄類型插入emp數據表中。
注意:%ROWTYPE與%TYPE一樣,只提供類型信息,並不能保證NOT NULL約束。
除了使用%ROWTYPE定義表列類型的變量外,還可以用來定義游標類型的變量,使用%ROWTYPE指定游標類型的變量,變量的值將是游標的SELECT語句查詢出來的值,。
下面代碼定義了游標emp_cursor,使用%ROWTYPE指定emp_cursor類型的變量。
DECLARE
CURSOR emp_cursor --定義游標類型
IS
SELECT empno , ename , job , sal , hiredate
FROM emp;
--使用%ROWTYPE定義了游標類型的變量
v_emp emp_cursor%ROWTYPE;
BEGIN
OPEN emp_cursor;
--循環並提取游標數據
LOOP
FETCH emp_cursor
INTO v_emp;
--要注意游標移動到最尾部退出游標
EXIT WHEN emp_cursor%NOTFOUND;
--輸出游標數據
DBMS_OUTPUT.put_line( v_emp.empno
||''
||v_emp.ename
||''
||v_emp.job
||''
||v_emp.sal
||''
||TO_CHAR(v_emp.hiredate,'YYYY-MM-DD')
);
END LOOP;
--關閉游標
CLOSE emp_cursor;
END;
/
代碼定義了游標emo_cursor,然后定義了該游標類型的v_emp變量,使用%ROWTYPE指定類型為游標返回類型,通過提取游標的FETCH-INTO語句,一次將一行數據寫入v_emp變量中,然后使用DBMS_OUTPUT.put_line來輸出結果值。
參考Oracle PL/SQL從入門到精通 清華大學出版社 作者:丁士鋒