本文介紹了自訂子類型的文法及樣本等內容。
文法
PL/SQL允許使用者自訂子類型(subtype),即在基本類型的基礎上增加一些限制。
自訂子類型定義的文法如下:
SUBTYPE subtype_name IS base_type
[precision [, scale ] | RANGE low_value .. high_value ] [ NOT NULL ];樣本
DECLARE
SUBTYPE subtype_char IS VARCHAR(10);
sub_var subtype_char;
base_var VARCHAR(10);
BEGIN
NULL;
END;其中,sub_var和base_var的類型實際上是一致的,都表示了一個長度受到限制的varchar類型。基本類型可以是任何標量或使用者定義的PL/SQL資料類型說明符。例如,CHAR或RECORD。
樣本一:
DECLARE TYPE r_type IS RECORD(id INT, name VARCHAR(10)); SUBTYPE subtype_record IS r_type; rec subtype_record; BEGIN rec.id := 1; rec.name := 'a'; RAISE NOTICE 'rec = %', rec; END;結果顯示如下:
NOTICE: rec = (1,a) DO樣本二:
DECLARE SUBTYPE subtype_char IS VARCHAR; SUBTYPE sub_subtype_char IS subtype_char; sub_var sub_subtype_char; BEGIN sub_var := 'a'; RAISE NOTICE 'sub_var = %', sub_var; END;結果顯示如下:
NOTICE: sub_var = a DO
無約束的子類型
無約束的子類型只是其基本類型的另一個名稱,因此它和它的基本類型擁有相同的值集。相同基本類型的子類型之間,或者基本類型與子類型之間進行賦值時,不產生資料類型轉換。無約束的子類型定義文法如下:
SUBTYPE subtype_name IS base_type;受約束的子類型
受約束的子類型僅具有其基本類型的值的子集。如果基本類型允許指定大小、精度和小數位元或值範圍,則可以為其子類型指定這些限制。受約束的子類型定義文法如下:
SUBTYPE subtype_name IS base_type
{ precision [, scale ] | RANGE low_value .. high_value } [ NOT NULL ]樣本
您可以使用NOT NULL關鍵字對使用該子類型的變數施加非空約束,也可以對基本類型為PLS_INTEGER的子類型使用RANGE關鍵字來施加取值範圍的約束。
受約束的子類型可以隱式轉換為其基本類型,但只有當值不違反子類型的約束時,基本類型才能隱式轉換為受約束的子類型。
在一個受約束子類型的變數賦值給另一個受約束子類型的變數時,不僅要滿足隱式轉換的要求,還需要滿足目標子類型的各項約束。
以下展示了一些在賦值時不滿足約束條件的樣本:
精度約束
DECLARE SUBTYPE subtype_number IS NUMBER(8,2); var1 subtype_number; var2 subtype_number; BEGIN var1 := 100000.00; -- 賦值成功 RAISE NOTICE 'var1 = %' , var1; var2 := 1000000.00; -- 賦值失敗 END;顯示結果如下:
NOTICE: var1 = 100000 ERROR: numeric field overflow DETAIL: A field with precision 8, scale 2 must round to an absolute value less than 10^6. CONTEXT: PL/SQL assignment "var2 := 1000000.00"取值範圍約束
DECLARE SUBTYPE subtype_range IS PLS_INTEGER RANGE 0..9; var subtype_range := 4; -- 賦值成功 BEGIN RAISE NOTICE 'var = %', var; var := 10; -- 賦值失敗 END;顯示結果如下:
NOTICE: var = 4 ERROR: the assignment of variable "var" is out of range, since it's declared between 0 and 9 CONTEXT: PL/SQL function inline_code_block line 6 at assignment非空約束
DECLARE SUBTYPE subtype_range IS INT NOT NULL; var subtype_range := 1; BEGIN RAISE NOTICE 'var = %', var; var := NULL; -- 賦值失敗 END;顯示結果如下:
NOTICE: var = 1 ERROR: null value cannot be assigned to variable "var" declared NOT NULL CONTEXT: PL/SQL function inline_code_block line 5 at assignment隱式類型轉換
DECLARE SUBTYPE subtype_int IS INT; SUBTYPE subtype_char IS CHAR(3); var1 subtype_int := 100; var2 subtype_char; BEGIN var2 := var1; -- 賦值成功 RAISE NOTICE 'var2 = %', var2; var1 := 1000; var2 := var1; -- 賦值失敗 END;顯示結果如下:
NOTICE: var2 = 100 ERROR: value too long for type character(3 char) CONTEXT: PL/SQL function inline_code_block line 10 at assignment
子類型作為局部函數的入參類型和傳回值類型
子類型和其他局部類型一樣,可以作為局部函數的入參類型和傳回值類型。
樣本
DECLARE
SUBTYPE sub_type IS VARCHAR(20);
PROCEDURE outer_proc IS
outer_var sub_type; -- 使用外層的局部類型sub_type
FUNCTION inner_func(name sub_type) RETURN sub_type IS
BEGIN
RETURN name || 'inner'; -- 返回了類型為sub_type的傳回值
END;
BEGIN
outer_var := inner_func('outer-'); -- 調用局部函數inner_func
RAISE NOTICE '%', outer_var;
END;
BEGIN
outer_proc; -- 首先調用局部過程outer_proc
END;結果顯示如下:
NOTICE: outer-inner
DO說明
由於OUT類型的入參會把傳入變數初始化為NULL,因此如果入參類型為具有非空約束的子類型時,會直接報錯:
DECLARE
SUBTYPE sub_type IS PLS_INTEGER NOT NULL;
a sub_type := 1;
PROCEDURE proc_test(id OUT sub_type) IS
BEGIN
NULL;
END;
BEGIN
proc_test(a); -- 報錯
END;顯示結果如下:
ERROR: null value cannot be assigned to variable "a" declared NOT NULL
CONTEXT: PL/SQL function inline_code_block line 3 at CALL