# Create Type Basic
- 使用 type 建表可以局限于只为这张表提供对应的属性或方法
-- way 1 | |
create or repalce type type_name as object ( | |
field_name type, | |
field_name type, | |
... | |
); | |
-- way 2 | |
Create or replace type type_name of custom_type; |
# AS OBJECT
create or replace type t1 as object ( | |
userid varchar2(100), | |
username varchar2(200) | |
); | |
create table user1 of t1; |
# OF CUSTOM_TYPE
example 1: | |
create or replace type t2 as table of varchar2(10); | |
example 2: | |
create or replace type t3 as varray(10) of varchar2(10); | |
example 3: | |
declare | |
v_array t3:= t3('a'); | |
begin | |
v_array.extend; | |
v_array(2):= 'b'; | |
v_array.extend; | |
select 'c' into v_array(3) from dual; | |
for i in 1..v_array.count loop | |
dbms_output.put_line(v_array(i)); -- a b c | |
end loop; | |
end; |
# Type Function
# Member Function
-- Create Type Defined | |
create or replace type userinfo_type as object( | |
userid varchar(100), | |
username varchar2(200), | |
gender number, | |
age number, | |
member function getGender(gender in number) return varchar2, | |
member function setGender(gender in varchar2) return varchar2, | |
member function getYear(age in number) return number, | |
pragma restrict_references(getGender, rnps), | |
pragma restrict_references(setGender, wnps) | |
); | |
/* | |
RNDS: (Read No Database State) 表示该 subprogram 不会查询 (query) 数据库中的表: ORA-00452 | |
WNDS: (Write No Database State) 表示该 subprogram 不会改变数据库中的表的数据 | |
RNPS: (Read No Package State) 不访问包中的变量 | |
WNPS:(Write No Package State) 不改变包中的变量值 | |
*/ | |
-- Create Type Body | |
create or replace type body userinfo_type as | |
member function getGender(gender in number) return varchar2 | |
is | |
begin | |
if gender = 0 then return '男'; end if; | |
return '女'; | |
end; | |
member function setGender(gender in varchar2) return varchar2 | |
is | |
begin | |
if gender = '男' then return 0; end if; | |
return 1; | |
end; | |
member function getYear(age in number) return number | |
is | |
begin | |
return extract(year from sysdate) - age; | |
end; | |
end; |
- Member Function Test
create table userinfo of userinfo_type; | |
insert into userinfo values('001','jack', '0', 18); | |
insert into userinfo values('002', 'annie', '1', 21); | |
commit; | |
select t.userid, t.username, t.getGender(gender) getGender, t.setGender('男') setGender, t.getYear(age) getYear from userinfo t; |
# Static Function
-- create type | |
create or replace type typ_calendar force as object( | |
year varchar2(10), | |
month varchar2(10), | |
Sunday varchar2(10), | |
Monday varchar2(10), | |
Tuesday varchar2(10), | |
Wednesday varchar2(10), | |
Thursday varchar2(10), | |
Friday varchar2(10), | |
Saturday varchar2(10), | |
curday varchar2(10), | |
member function format( | |
curday date := sysdate, | |
fmtlen pls_integer := 8 | |
) return typ_calendar, | |
static function format_day( | |
day varchar2 | |
) return varchar2 | |
); | |
-- create type body | |
create or replace type body typ_calendar as | |
member function format( | |
curday date := sysdate, | |
fmtlen pls_integer := 8 | |
) return typ_calendar as | |
v_calendar typ_calendar := typ_calendar('','','','','','','','','',''); | |
v_dd varchar2(2) := to_char(curday, 'dd'); | |
function fmt( fmtstr varchar2 )return varchar2 as | |
begin | |
return lpad(fmtstr, fmtlen, ' '); | |
end fmt; | |
begin | |
v_calendar.year := year; | |
v_calendar.month := month; | |
v_calendar.Sunday := fmt(Sunday); | |
v_calendar.Monday := fmt(Monday); | |
v_calendar.Tuesday := fmt(Tuesday); | |
v_calendar.Wednesday := fmt(Wednesday); | |
v_calendar.Thursday := fmt(Thursday); | |
v_calendar.Friday := fmt(Friday); | |
v_calendar.Saturday := fmt(Saturday); | |
v_calendar.Curday := nvl(self.Curday, fmt(to_char(curday, 'dd'))); | |
dbms_output.put_line(self.curday ); | |
if (YEAR || lpad(MONTH, 2, '0') = to_char(curday, 'yyyymm')) then | |
case v_dd | |
when Sunday then | |
v_calendar.Sunday := fmt('【' || Sunday || '】'); | |
when Monday then | |
v_calendar.Monday := fmt('【' || Monday || '】'); | |
when Tuesday then | |
v_calendar.Tuesday := fmt('【' || Tuesday || '】'); | |
when Wednesday then | |
v_calendar.Wednesday := fmt('【' || Wednesday || '】'); | |
when Thursday then | |
v_calendar.Thursday := fmt('【' || Thursday || '】'); | |
when Friday then | |
v_calendar.Friday := fmt('【' || Friday || '】'); | |
when Saturday then | |
v_calendar.Saturday := fmt('【' || Saturday || '】'); | |
else null; | |
end case; | |
end if; | |
return v_calendar; | |
end format; | |
static function format_day (day varchar2) return varchar2 as | |
v_day number := to_number(day); | |
v_value varchar2(20); | |
begin | |
case | |
when v_day = 1 then v_value:= '星期一'; | |
when v_day = 2 then v_value:= '星期二'; | |
when v_day = 3 then v_value:= '星期三'; | |
when v_day = 4 then v_value:= '星期四'; | |
when v_day = 5 then v_value:= '星期五'; | |
when v_day = 6 then v_value:= '星期六'; | |
when v_day = 7 then v_value:= '星期日'; | |
else v_value:= '日期天数不合法,'; | |
end case; | |
return v_value; | |
end; | |
end; |
- Static Function Test
create table calendar of typ_calendar; | |
-- 插入数据使用 calendar.format 进行类型转换格式化 | |
insert into calendar | |
select typ_calendar('2021', '06', '01', '02', '03', '04', '05', '06', '07','01').format() typ_calendar from dual; | |
insert into calendar | |
select typ_calendar('2022', '08', '01', '02', '03', '04', '05', '06', '07','02').format() typ_calendar from dual; | |
insert into calendar | |
select typ_calendar('2023', '05', '01', '02', '03', '04', '05', '06', '07','').format() typ_calendar from dual; | |
commit; | |
-- Member Function Test | |
-- 1.format 是 member(成员函数),可以直接 (表别名.function) 调用 member function 修饰的方法 | |
select t.format(sysdate, 8) from calendar t; | |
-- 2. 直接通过 (type.function) 调用 member function 修饰的方法,会报错:ORA-06553: PLS-306 | |
-- select typ_calendar.format(sysdate, 8) from calendar; | |
-- 3. 调用静态方法时不能使用实例值: ORA-06553: PLS-587 | |
-- select typ_calendar('2022', '08', '01', '02', '03', '04', '05', '06', '07','02').format().format_day('01') typ_calendar from dual; | |
-- Static Function Test | |
-- 1. 将数字转星期,通过 type 直接调用 (static function) 修饰的静态方法是没有问题的 | |
select typ_calendar.format_day(curday) from calendar; | |
-- 2. 调用静态方法时不能使用实例值: ORA-06553: PLS-587 | |
-- select t.format_day('01') from calendar t; |
# Constructor Function
- 定义构造方法必须使用关键字 constructor,构造方法名称必须要与对象类型名称一致。
- 下方定义了三个构造函数,相同构造名称,含有不同个数参数(你可以理解为 java 里面的重载)
-- create type | |
create or replace type type_user as object ( | |
name varchar2(100), | |
year number, | |
month number, | |
day number, | |
Birthdate varchar2(200), | |
constructor function type_user(name varchar2, year number) | |
return self as result, | |
constructor function type_user(name varchar2, year number, month number) | |
return self as result, | |
constructor function type_user(name varchar2, year number, month number, day number) | |
return self as result | |
); | |
-- create type Body | |
create or replace type body type_user | |
as | |
-- 当只传入了参数 year 时,他的生日信息只会显示 年份 | |
constructor function type_user(name varchar2, year number) | |
return self as result as | |
begin | |
self.name := name; | |
self.year := year; | |
self.Birthdate := year; | |
return; | |
end; | |
-- 当传入了参数 year、month 时,他的生日信息会显示 年份 - 月份 | |
constructor function type_user(name varchar2, year number, month number) | |
return self as result as | |
begin | |
self.name := name; | |
self.year := year; | |
self.month := month; | |
self.Birthdate := year||'-'||month; | |
return; | |
end; | |
-- 当传入了参数 year、month、day 时,他的生日信息会完整的显示 年 - 月 - 日 | |
constructor function type_user(name varchar2, year number, month number,day number) | |
return self as result as | |
begin | |
self.name := name; | |
self.year := year; | |
self.month := month; | |
self.day := day; | |
self.Birthdate := year||'-'||month||'-'||day; | |
return; | |
end; | |
end; |
- Constructor Function Test
-- 调用 | |
declare | |
u1 type_user; | |
u2 type_user; | |
u3 type_user := type_user('C',2003, 03, 040); | |
begin | |
-- 我们可以调用默认 3 个参数的构造函数(因为定义了 3 个属性) | |
u1 := new type_user('A', 2001); | |
dbms_output.put_line(u1.name || ' Birthdate:' || u1.Birthdate); | |
u2 := new type_user('B', 2002, 02); | |
dbms_output.put_line(u2.name || ' Birthdate:' || u2.Birthdate); | |
dbms_output.put_line(u3.name || ' Birthdate:'|| u3.Birthdate); | |
/** | |
Result | |
A Birthdate:2001 | |
B Birthdate:2002-2 | |
C Birthdate:2003-3-40 | |
*/ | |
end; |
- 注意构造函数的存在对在使用 DMl 语句,没有进行类型转换时是不会产生影响的。
create table users of type_user; | |
-- 默认是不会参数影响的 | |
select 'C',2003, 03, 04 from users; | |
-- 需要进行 type_user 转换 | |
select type_user('C',2003) from dual; | |
select type_user('C',2003, 03) from dual; | |
select type_user('C',2003, 03, 04) from dual; |
# Abstract Type
create or replace type other_type as object ( | |
sports varchar2(200), | |
hobby varchar2(200) | |
); | |
create or replace type user_type as object( | |
userid varchar2(100), | |
username varchar2(200), | |
other other_type | |
); |
# Abstract Type Test
create table userinfo2 of user_type; | |
-- insert | |
insert into userinfo2(userid, username, other) values('001', 'jack', other_type('ping pong', 'animation')); | |
insert into userinfo2(userid, username, other) values('002', 'lisa', other_type('badminton', 'animation')); | |
commit; | |
select t.userid, t.username, t.other.sports sports, t.other.hobby hobby from userinfo2 t; | |
-- update | |
update userinfo2 t set t.username = 'jerry', t.other.sports = 'football' where userid = '001'; | |
commit; | |
select t.userid, t.username, t.other.sports sports, t.other.hobby hobby from userinfo2 t; |
# Type Extends
- a final object type is a type from which cannot be derived
- 最终对象类型是无法派生的类型
# Not Final & Final
-- not final | |
create or replace type this_type_not_final as object( | |
money number, | |
member function sum(x in number) return number | |
) not final; | |
create or replace type body this_type_not_final as | |
member function sum(x in number) return number | |
is | |
begin | |
return money * x; | |
end sum; | |
end; | |
-- final | |
create or replace type this_type_final as object( | |
color varchar2(200), | |
material varchar2(200), | |
member function sum(x in number, y in number) return number | |
); | |
create or replace type body this_type_final as | |
member function sum(x in number, y in number) return number | |
is | |
begin | |
return x + y; | |
end sum; | |
end; |
# Type Derive
-- The following type can be derived because the base type is not final. | |
-- 可以派生以下类型,因为基础类型不是最终类型 (not final)。 | |
create or replace type derived_from_NOT_final under this_type_NOT_final ( | |
member procedure bar | |
); | |
-- The following type can not be derived because the base type is final. | |
-- 无法派生以下类型,因为基类型是最终类型 (final)。 | |
create or replace type derived_from_final under this_type_final ( | |
member procedure bar | |
); | |
-- Trying to derive from a final type gives a PLS-00590: attempting to create a subtype UNDER a FINAL type. | |
-- pls-00590: 正在尝试创建一个最终类型的子类型 |
# Final Function
- not final member procedures/functions
- 不是最终成员程序 / 函数
-- create type | |
create or replace type type_member_isfinal as object ( | |
x number, | |
not final member function NOT_FINAL_func(y in number) return number, | |
final member function FINAL_func (y in number) return number | |
) not final; | |
-- create type body | |
create or replace type body type_member_isfinal as | |
not final member function NOT_FINAL_func(y in number) return number | |
is | |
begin | |
return x + y; | |
end; | |
final member function FINAL_func(y in number) return number | |
is | |
begin | |
return x - y; | |
end; | |
end; |
# Overriding Function
- a member function (or procedure) can be overriden if it is declared not final in the base class
- 如果成员函数(或过程)在基类中声明不是 final,则可以重写该函数(或过程)
create or replace type type_override_member_isfinal under type_member_isfinal ( | |
overriding member function NOT_FINAL_func(y in number) return number | |
); | |
-- 以下内容不起作用,因为无法重写最终成员函数 | |
create or replace type type_override_member_isfinal under type_member_isfinal ( | |
overriding member function FINAL_func(y in number) return number | |
); | |
-- pls-00637: 无法覆盖或隐藏 final 方法 |
- 建议参考:http://adp-gmbh.ch/ora/plsql/oo/not_final.html