SUBTYPE

SUBTYPE
是一种强大的特性,允许开发者基于现有数据类型定义新的子类型,并可以为这些子类型添加约束条件(如范围、精度等)。这种特性在数据建模和程序设计中具有显著优势,例如:

  • 增强数据一致性:通过为数据类型添加约束,确保数据符合业务规则。

  • 提高代码可读性:使用自定义的子类型可以更清晰地表达代码意图。

  • 简化数据类型管理:允许基于现有类型派生新类型,减少重复定义。

说明:

该功能在V9.0.5及以后的版本中支持。

使用SUBTYPE类型

说明

SUBTYPE
类型可以使用标量类型、复合类型、record类型和subtype类型作为基类型。可以用在存储过程、函数、匿名块、包中使用,也可以作为参数和返回值类型使用。

语法:

SUBTYPE subtype_name IS base_type

示例

匿名块中使用subtype

示例1:在匿名块中定义subtype类型并使用

DECLARE

SUBTYPE typ1 IS integer;

val1 typ1 := 123;

BEGIN

raise notice 'val1: %', val1;

END;

/

示例2:在匿名块中定义基于数组和subtype类型的subtype类型并使用

DECLARE

SUBTYPE my_subtype1 IS int[];

SUBTYPE my_subtype2 IS my_subtype1;

val1 my_subtype2;

BEGIN

val1 := ARRAY[1,2,3,4,5];

raise notice 'val1: %', val1[2];

END;

/

示例3:在匿名块中定义基于复合类型的subtype类型并使用

CREATE TYPE rec_type AS (id INTEGER, name VARCHAR(30));

DECLARE

SUBTYPE typ1 IS rec_type;

val1 typ1;

BEGIN

val1.id := 101;

val1.name := 'John';

raise notice 'val1: %', val1;

END;

/

存储过程中使用subtype

示例:在存储过程中定义subtype类型并使用

CREATE OR REPLACE PROCEDURE pr1 AS

SUBTYPE typ1 IS integer;

val1 typ1 := 123;

BEGIN

raise notice 'val1: %', val1;

END;

/

CALL pr1();

函数中使用subtype

示例:在函数中定义subtype类型并作为参数和返回值使用

CREATE OR REPLACE FUNCTION func1 RETURN INTEGER AS

SUBTYPE typ1 IS integer;

val1 typ1 := 123;

val2 typ1;

FUNCTION test_func1(p1 typ1) RETURN typ1 AS

BEGIN

RETURN p1;

END;

BEGIN

val2 := test_func1(val1);

raise notice 'val2: %', val2;

RETURN 1;

END;

/

SELECT func1() FROM DUAL;

包中使用subtype

示例:在包中定义subtype类型并使用

CREATE OR REPLACE PACKAGE my_package AS

SUBTYPE age IS INTEGER;

PROCEDURE display_employee_info(p_age IN age);

FUNCTION get_default_age RETURN age;

END my_package;

CREATE OR REPLACE PACKAGE BODY my_package AS

PROCEDURE display_employee_info(p_age IN age) IS

BEGIN

raise notice 'Age: %', p_age;

END display_employee_info;

FUNCTION get_default_age RETURN age IS

BEGIN

RETURN 30;

END get_default_age;

END my_package;

DECLARE

v_age my_package.age := 45;

BEGIN

my_package.display_employee_info(p_age => v_age);

raise notice 'Default age: %', my_package.get_default_age();

END;

/

使用record作为基类型

示例:使用record作为基类型

DECLARE

TYPE rec_type IS RECORD (id INTEGER, name VARCHAR2(30));

SUBTYPE my_subtype1 IS rec_type;

SUBTYPE my_subtype2 IS my_subtype1;

val1 my_subtype1;

val2 my_subtype2;

BEGIN

val1.id := 100;

val1.name := 'John';

raise notice 'val1: %', val1;

val2.id := 100;

val2.name := 'John';

raise notice 'val2: %', val2;

END;

/

使用cursor和rowtype作为基类型

示例:使用cursor和rowtype作为基类型

CREATE TABLE employees(id INTGER, name VARCHAR2(30));

INSERT INTO employees VALUES(100, 'John');

DECLARE

TYPE empcurtyp IS REF CURSOR RETURN employees%ROWTYPE;

SUBTYPE my_subtype1 IS empcurtyp;

SUBTYPE my_subtype2 IS my_subtype1;

SUBTYPE my_subtype3 IS employees%ROWTYPE;

SUBTYPE my_subtype4 IS my_subtype3;

cursor1 my_subtype1;

cursor2 my_subtype2;

val1 my_subtype3;

val2 my_subtype4;

BEGIN

OPEN cursor1 FOR SELECT * FROM employees;

FETCH cursor1 INTO val1;

raise info 'al1: %', val1;

CLOSE cursor1;

OPEN cursor2 FOR SELECT * FROM employees;

FETCH cursor2 INTO val2;

raise info 'val2: %', val2;

CLOSE cursor2;

END;

/

SUBTYPE类型支持约束

定义subtype类型支持添加多种约束,包括非空约束,长度约束和范围约束。

非空约束

语法:

SUBTYPE subtype_name IS base_type [ NOT NULL ]

示例:

DECLARE

SUBTYPE typ1 IS INTEGER NOT NULL;

val1 typ1 := 123;

val2 typ1; --err

BEGIN

val2 := val1;

raise notice 'val2: %', val2;

val2 := NULL; --err

END;

/

因为将val2设置为null,所以上述语句会报错:

variable "val2" must have a default value, since it's declared NOT
NULL

长度约束

语法:

SUBTYPE subtype_name IS base_type [ precision [, scale ]] [ NOT
NULL ]

示例:

DECLARE

SUBTYPE str_subtype IS VARCHAR2(10);

v_str1 str_subtype(5) := 'Hello';

v_str2 str_subtype;

BEGIN

v_str1 := 'HelloOK'; --err

v_str2 := 'HelloOK';

raise notice 'v_str1: %', v_str1;

END;

/

因为 v_str1的值超过了设定长度,所以上述语句会报错:

ERROR: value too long for type varchar2(5 byte)

范围约束

目前仅支持对INTEGER类型使用范围约束。

语法:

SUBTYPE subtype_name IS base_type

[ RANGE low_value .. high_value ] [ NOT NULL ]

示例:

DECLARE

SUBTYPE typ1 IS INTEGER RANGE 0..9;

SUBTYPE typ2 IS INTEGER RANGE 10..99;

SUBTYPE typ3 IS INTEGER RANGE 0..99;

val1 typ1 := 4;

val2 typ2 := 35;

val3 typ3;

BEGIN

raise notice 'val1: %', val1;

val3 := val1;

val1 := val2; --err

val2 := val1; --err

END;

/

因为val1 和val2的值超过了设置的范围,所以上述语句会报错:

ERROR: numeric or value error