您的位置:首页 > 数据库 > Oracle

ORACLE PL/SQL 对象(object)学习笔记(一)

2009-10-27 23:25 881 查看
 1、对象类型规范
 
创建对象类型规范的语法如下
 
CREATE [OR REPLACE] TYPE [schema.] type_name

[AUTHID {CURRENT_USER|DEFINER}] AS OBJECT (

Attribute1 datatype,

[attribute2 datatype,…]

[method 1]

[method 2]);

/

 
 
 
其中AUTHID指示将来执行该方法时,必须使用在创建时定义的CURRENT_USER或DEFINER的权限集合。CURRENT_USER是调用该方法的用户,DEFINER是该对象类型的所有者。

 

 
1)属性
属性的声明有一些限制,包括:
 

属性的声明必须出现在方法的声明以前。

数据类型可以是任何数据库数据类型,但是不能包括ROWID,UROWID,LONG,LONG RAW,NCHAR,NCLOB,NVARCHAR2类型,以及PL/SQL的专用类型或在PL/SQL包中定义的类型。

不能使用那些只能在PL/SQL中使用而不能在数据库中使用的数据类型。这些类型包括BINARY_INTEGER,BOOLEAN,PLS_INTEGER,RECORD和REF CURSOR。

不能使用NOT NULL约束,但是可以通过在对象实例上定义一个数据库触发器来达到相同效果。

属性列表中至少必须有一个属性。

不能使用默认值。

 
注意:不能直接在属性或对象类型上使用%TYPE和%ROWTYPE。但是可以在对象实例的属性上使用它们。
 
-- This example works fine.  %TYPE is applied

-- to the variable, not the object type.

DECLARE

v_discount_price   discount_price_obj;

v_price           v_discount_price.price%TYPE;

BEGIN

NULL;

END;

/

-- This example throws an exception.  %TYPE is applied

-- directly to the object type.

DECLARE

v_price           discount_price_obj.price%TYPE;

BEGIN

NULL;

END;

/
  
 
复合对象类型
 
复合对象类型可以以某个属性的数据类型的形式,包含另一个对象类型。
 
CREATE OR REPLACE TYPE discount_price_obj AS OBJECT (

discount_rate  NUMBER(10,4),

price          NUMBER(10,2),

MEMBER FUNCTION discount_price RETURN NUMBER)

INSTANTIABLE

FINAL;

/

CREATE OR REPLACE TYPE inventory_obj AS OBJECT (

item_id        NUMBER(10),

num_in_stock   NUMBER(10),

reorder_status VARCHAR2(20),

price       REF   discount_price_obj);

/
  
 
2)方法
方法就是过程或函数,它们是在属性声明之后进行声明的。声明方法的拓展语义如下
 
 
[STATIC | MEMBER] PROCEDURE procedure_spec,

[STATIC | MEMBER | CONSTRUCTOR] FUNCTION function_spec,

[MAP | ORDER] MEMBER FUNCTION function_spec,

Pragma_declaration
  
 
该声明和包规范的声明没有太多的区别。二者之间的主要差别是STATIC,CONSTRUCTOR和MEMBER关键字的使用。MAP和ORDER的作用是确定对象类型的排列顺序。
 
MEMBER方法
成员方法是基于对象实例调用的,而不是基于对象类型调用的。
 
STATIC方法
静态方法独立于对象实例,也不能在对象类型主体中引用这个对象的属性。
 
CONSTRUCTOR方法
到目前为止,我们只看到了显式声明的成员方法和静态方法,它们通过过程或函数作用于对象属性。另一方面,构造函数一直都是系统定义的函数,函数返回一个实例化的对象,并带有一些参数,这些参数就是相应对象的属性值。ORACLE为每一个对象类型都预定义了一个构造函数,这个方法的名称和属性与对象类型相同。
但是,从ORACLE 9i R2开始,ORACLE开始允许用户自定义构造函数,这种用户自定义的构造函数使我们可以重写系统定义的构造函数,或者添加其他的构造函数。
 
 
2、对象类型主体
对象类型主体与包类似。规范是由属性和方法的声明组成的,只有方法是在对象类型主体中实现的,如果对象类型规范中只包含属性,那么就不需要对象类型主体了。
 
创建对象类型主体的语法如下
 
 
CRAETE [OR REPLACE] TYPE BODY [schema.] type_name {IS | AS}

[STATIC | MEMBER] PROCEDURE procedure_body

[STATIC | MEMBER | CONSTRUCTOR] FUNCTION function_body

[MAP | ORDER] MEMBER function_body

END;
 
 
1)SELF参数
关键字SELF引用当前对象实例。像JAVA语言的THIS关键字一样,可以使用它引用整个对象,也可以使用它引用当前对象的方法或属性。
 
SELF被自动声明为MEMBER方法的第一个参数,默认时,如果没有进行显式地限定,在MEMBER函数中整个参数的模式为IN,在MEMBER过程中这个参数的模式为IN OUT。
不能将其声明为OUT模式,另外,SELF还必须与原始对象的数据类型相同。
 
就实例来说,没有必要包含SELF关键字,因为默认时对属性的引用使用的就是当前对象。
 
如下例所示
 
CREATE OR REPLACE TYPE BODY discount_price_obj

AS

MEMBER FUNCTION discount_price

RETURN NUMBER

IS

BEGIN

RETURN (SELF.price * (1 - SELF.discount_rate));

END discount_price;

END;

/

 
 
 
虽然在上面这个示例中SELF作为它的一个可选关键字,可是在用户自定义构造函数还必须在返回子句中使用RETURN SELF AS RESULT。

 

 
CREATE OR REPLACE TYPE BODY discount_price_obj

AS

CONSTRUCTOR FUNCTION discount_price_obj (price NUMBER)

RETURN SELF AS RESULT

AS

BEGIN

SELF.price := price * .9;

RETURN;

END discount_price_obj;

END;

/

 
 
 
试图在返回语句中使用除了SELF以外的任何语句,都会引发下面的异常

 

PLS-00659 : constructor method must return SELF AS RESULT
 
2)MAP和ORDER 方法
MAP和ORDER方法可以对两个对象进行比较。在这里首先给出适用于这二者的公共规则:

每个对象上最多只能允许有一个MAP或ORDER方法。

不能在同一个对象上既定义MAP方法,又定义ORDER方法。

MAP和ORDER方法可以比较程序代码中的两个对象。如果没有使用它们,比较程序代码中的两个对象就会引发异常。但是,在SQL语句中仍然可以进行相等性比较,因为这种比较只是比较对象的每一个属性。

 
MAP方法
ORACLE需要比较两个对象(布尔比较),或使用GROUP BY,ORDER BY,或DISTINCT子句比较对象的时候,它就会调用MAP函数,将对象转换为可以存储的类型。在使用大群对象的时候,MAP方法就比ORDER方法更加有效,因为它将整个对象集转换为一种更简单的类型(以散列函数的形式进行操作),然后再对这种类型进行排序。MAP方法只带一个SELF参数,返回类型是DATE,NUMBER,VARCHAR2,CHAR或REAL的标量类型。
 
下面看一个使用MAP的示例
 
CREATE OR REPLACE TYPE book_obj AS OBJECT (

isbn        CHAR (10),

title       VARCHAR2 (100),

num_pages   NUMBER,

MAP MEMBER FUNCTION return_isbn

RETURN CHAR

);

/

CREATE OR REPLACE TYPE BODY book_obj

AS

MAP MEMBER FUNCTION return_isbn

RETURN CHAR

IS

BEGIN

RETURN SELF.isbn;

END return_isbn;

END;

/

--现在就可以通过isdn来比较两个对象

DECLARE

v_book1   book := book ('72121203', 'Oracle DBA 101', 563);

v_book2   book := book ('72122048', 'Oracle 8i: A Beginner''s Guide', 765);

BEGIN

IF v_book1 < v_book2

THEN

DBMS_OUTPUT.put_line (v_book1.title || ' < ' || v_book2.title);

ELSIF v_book1 = v_book2

THEN

DBMS_OUTPUT.put_line (v_book1.title || ' = ' || v_book2.title);

ELSE

DBMS_OUTPUT.put_line (v_book1.title || ' > ' || v_book2.title);

END IF;

END;

/

 
ORDER方法
ORDER方法与MAP方法在功能上非常相似,但是它们的执行有些细微的区别。该方法的输入参数的数据类型是一个对象类型的参数,返回类型只能是NUMBER类型。
 
同样对于上面MAP方法的那个示例,用ORDER来实现,如下所示
 
CREATE OR REPLACE TYPE book_obj AS OBJECT (

isbn        CHAR (10),

title       VARCHAR2 (100),

num_pages   NUMBER,

ORDER MEMBER FUNCTION compare_book (p_isbn IN BOOK_OBJ)

RETURN NUMBER

);

/

CREATE OR REPLACE TYPE BODY book_obj

AS

ORDER MEMBER FUNCTION compare_book (p_isbn IN BOOK_OBJ)

RETURN NUMBER

IS

BEGIN

IF p_isbn.isbn < SELF.isbn

THEN

RETURN 1;

ELSIF p_isbn.isbn > SELF.isbn

THEN

RETURN -1;

ELSE

RETURN 0;

END IF;

END compare_book;

END;

/

SET SERVEROUTPUT ON SIZE 1000000

DECLARE

v_book1   book := book ('72121203', 'Oracle DBA 101', 563);

v_book2   book := book ('72122048', 'Oracle 8i: A Beginner''s Guide', 765);

BEGIN

IF v_book1 < v_book2

THEN

DBMS_OUTPUT.put_line (v_book1.title || ' < ' || v_book2.title);

ELSIF v_book1 = v_book2

THEN

DBMS_OUTPUT.put_line (v_book1.title || ' = ' || v_book2.title);

ELSE

DBMS_OUTPUT.put_line (v_book1.title || ' > ' || v_book2.title);

END IF;

END;

/
  
 
3、更改和删除类型
和其他类型数据类型相类似,你可以通过ALTER TYPE语句修改现有的对象类型。ALTER TYPE可以被用于编译类型规范或主体,或者向类型中添加方法。也可以使用DROP TYPE来删除类型。
 
1)ALTER TYPE…COMPILE
 
命令格式如下
 
ALTER TYPE type_name COMPILE[SPECIFICATION | BODY];
 
如果没有指定[SPECIFICATION | BODY],那么规范和主体都将被重新编译。
 
2)ALTER TYPE … REPLACE AS OBJECT
 
命令格式如下
 
ALTER TYPE type_name REPLACE AS OBJECT(object_type_specification);
 
这里的object_type_specification是一个完全的类型定义,这和在CREATE TYPE命令中定义是一样的。新的定义必须和旧的定义是完全一样的,除了新添加的方法以外。如果该类型的主体存在,那么它还并未生效的,因为没有在类型主体中定义新方法。
 
下面的例子说明了该命令的使用方法
 
/* Create a simple object type with two attributes and two methods. */

CREATE OR REPLACE TYPE DummyObj AS OBJECT (

f1 NUMBER,

f2 NUMBER,

MEMBER PROCEDURE Method1(x IN VARCHAR2),

MEMBER FUNCTION Method2 RETURN DATE

);

/

/* Create the type body. */

CREATE OR REPLACE TYPE BODY DummyObj AS

MEMBER PROCEDURE Method1(x IN VARCHAR2) IS

BEGIN

NULL;

END Method1;

MEMBER FUNCTION Method2 RETURN DATE IS

BEGIN

RETURN SYSDATE;

END Method2;

END;

/

SELECT object_name, object_type, status

FROM user_objects

WHERE object_name = 'DUMMYOBJ';

OBJECT_NAME  OBJECT_TYPE    STATUS

---------------------   ---------------------   ----------------

DEMMYOBJ        TYPE          VALID

DEMMYOBJ        TYPE BODY    VALID

/* Alter the type to add a new method.  This invalidates the type body. */

ALTER TYPE DummyObj REPLACE AS OBJECT (

f1 NUMBER,

f2 NUMBER,

MEMBER PROCEDURE Method1(x IN VARCHAR2),

MEMBER FUNCTION Method2 RETURN DATE,

MEMBER PROCEDURE Method3

);

SELECT object_name, object_type, status

FROM user_objects

WHERE object_name = 'DUMMYOBJ';

OBJECT_NAME  OBJECT_TYPE    STATUS

---------------------   ---------------------   ----------------

DEMMYOBJ        TYPE          VALID

DEMMYOBJ        TYPE BODY    INVALID

 
还可以给已有的类型添加或者删除属性

ALTER TYPE cd_obj
ADD ATTRIBUTE subtitle VARCHAR2(20)
 
ALTER TYPE cd_obj
DROP ATTRIBUTE subtitle
 
3)DROP TYPE

命令格式如下
 
DROP TYPE [schema.] type_name [FORCE];
 
如果FORCE选项没有被指定,那么仅当所有其他数据模式对象都不依赖于在命令中指定的对象类型时才会删除该对象类型。如果指定了FORCE选项,那么该对象将被删除,这有可能会使得其他依赖于该对象的其他对象失效。
 
DROP TYPE BODY可以用来仅仅删除对象类型的主体,但是规范和所有依赖对象保持不变,其命令格式如下
 
DROP TYPE BODY[schema.] type_name
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息