⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 第十章 pl-sql对象类型 - pl-sql用户指南与参考 - whatiswhat.htm

📁 sql初学者不错的教程
💻 HTM
📖 第 1 页 / 共 5 页
字号:
                              <TD noWrap>object_type_name.method() 
                            </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>方法的定义规则与打包子程序的相同,也分为说明和体两个部分。说明部分由一个方法名和一个可选的参数列表组成,如果是函数,还需要包含一个返回类型。包体就是一段能执行一个特殊任务的代码。</P>
                        <P>对于对象类型说明中的每个方法说明,在对象类型体中都必须有与之对应的方法体实现,除非这个方法是用关键字NOT 
                        INSTANTIABLE加以限定,它的意思就是方法体的实现只在子类中出现。为了使方法说明和方法体相匹配,PL/SQL编译器采用token-by- 
                        token的方式把它们的头部进行比较。头部必须精确匹配。</P>
                        <P>与属性相同,一个形式参数的声明也是由名称和数据类型组成。但是,参数的类型不能受到大小约束。数据的类型可以是任何Oracle类型,除了那些不适用于属性的类型。这些约束也适用于返回值的类型。</P>
                        <UL>
                          <LI>方法实现所允许使用的语言 </LI></UL>
                        <P>Oracle允许我们在PL/SQL、Java或C语言中实现对象方法。我们可以在Java或C语言中实现类型方法,只需提供一个调用说明即可。调用说明在Oracle的数据词典中公布了Java方法或外部C函数。它把程序的名称、参数类型和返回值信息映射到对应的SQL中去。 
                        </P>
                        <UL>
                          <LI>SELF参数 </LI></UL>
                        <P>MEMBER方法接受一个内置的SELF参数,它代表了对象类型的实例。不论显式或隐式声明,它总是第一个传入MEMBER方法的参数。但是,STATIC方法就不能接受或引用SELF。 
                        </P>
                        <P>在方法体中,SELF指定了被调用方法所属的对象实例。例如,方法transform把SELF声明为IN 
                        OUT参数: </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>CREATE</STRONG>&nbsp;<STRONG>TYPE</STRONG>&nbsp;Complex&nbsp;<STRONG>AS</STRONG>&nbsp;OBJECT&nbsp;(<BR>&nbsp;&nbsp;MEMBER&nbsp;<STRONG>FUNCTION</STRONG>&nbsp;transform&nbsp;(SELF&nbsp;<STRONG>IN</STRONG>&nbsp;<STRONG>OUT</STRONG>&nbsp;Complex)&nbsp;... 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>我们不能把SELF指定成其他数据类型。在MEMBER函数中,如果SELF没有声明的话,它的参数默认为IN。但是,在MEMBER过程中,如果SELF没有什么,那么它的参数模式默认为IN 
                        OUT。并且,我们不能把SELF的模式指定为OUT。 </P>
                        <P>如下例所示,方法可以直接引用SELF的属性,并不需要限定修饰词: </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>CREATE</STRONG>&nbsp;<STRONG>FUNCTION</STRONG>&nbsp;gcd(x&nbsp;<STRONG>INTEGER</STRONG>,&nbsp;y&nbsp;<STRONG>INTEGER</STRONG>)<BR>&nbsp;&nbsp;<STRONG>RETURN</STRONG>&nbsp;<STRONG>INTEGER</STRONG>&nbsp;<STRONG>AS</STRONG><BR>&nbsp;&nbsp;<EM>--&nbsp;find&nbsp;greatest&nbsp;common&nbsp;divisor&nbsp;of&nbsp;x&nbsp;and&nbsp;y</EM><BR>&nbsp;&nbsp;ans&nbsp;&nbsp;&nbsp;<STRONG>INTEGER</STRONG>;<BR><STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;<STRONG>IF</STRONG>&nbsp;(y&nbsp;&lt;=&nbsp;x)&nbsp;<STRONG>AND</STRONG>(x&nbsp;<STRONG>MOD</STRONG>&nbsp;y&nbsp;=&nbsp;0)&nbsp;<STRONG>THEN</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;ans&nbsp;&nbsp;&nbsp;&nbsp;:=&nbsp;y;<BR>&nbsp;&nbsp;<STRONG>ELSIF</STRONG>&nbsp;x&nbsp;&lt;&nbsp;y&nbsp;<STRONG>THEN</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;ans&nbsp;&nbsp;&nbsp;&nbsp;:=&nbsp;gcd(y,&nbsp;x);<BR>&nbsp;&nbsp;<STRONG>ELSE</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;ans&nbsp;&nbsp;&nbsp;&nbsp;:=&nbsp;gcd(y,&nbsp;x&nbsp;<STRONG>MOD</STRONG>&nbsp;y);<BR>&nbsp;&nbsp;<STRONG>END</STRONG>&nbsp;<STRONG>IF</STRONG>;<BR><BR>&nbsp;&nbsp;<STRONG>RETURN</STRONG>&nbsp;ans;<BR><STRONG>END</STRONG>;<BR><BR><STRONG>CREATE</STRONG>&nbsp;<STRONG>TYPE</STRONG>&nbsp;rational&nbsp;<STRONG>AS</STRONG>&nbsp;OBJECT(<BR>&nbsp;&nbsp;num&nbsp;&nbsp;&nbsp;<STRONG>INTEGER</STRONG>,<BR>&nbsp;&nbsp;den&nbsp;&nbsp;&nbsp;<STRONG>INTEGER</STRONG>,<BR>&nbsp;&nbsp;MEMBER&nbsp;<STRONG>PROCEDURE</STRONG>&nbsp;normalize,<BR>&nbsp;&nbsp;...<BR>);<BR><BR><STRONG>CREATE</STRONG>&nbsp;<STRONG>TYPE</STRONG>&nbsp;<STRONG>BODY</STRONG>&nbsp;rational&nbsp;<STRONG>AS</STRONG><BR>&nbsp;&nbsp;MEMBER&nbsp;<STRONG>PROCEDURE</STRONG>&nbsp;normalize&nbsp;<STRONG>IS</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;g&nbsp;&nbsp;&nbsp;<STRONG>INTEGER</STRONG>;<BR>&nbsp;&nbsp;<STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;g&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:=&nbsp;gcd(SELF.num,&nbsp;SELF.den);<BR>&nbsp;&nbsp;&nbsp;&nbsp;g&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:=&nbsp;gcd(num,&nbsp;den);&nbsp;&nbsp;&nbsp;<EM>--&nbsp;equivalent&nbsp;to&nbsp;previous&nbsp;statement</EM><BR>&nbsp;&nbsp;&nbsp;&nbsp;num&nbsp;&nbsp;&nbsp;&nbsp;:=&nbsp;num&nbsp;/&nbsp;g;<BR>&nbsp;&nbsp;&nbsp;&nbsp;den&nbsp;&nbsp;&nbsp;&nbsp;:=&nbsp;den&nbsp;/&nbsp;g;<BR>&nbsp;&nbsp;<STRONG>END</STRONG>&nbsp;normalize;<BR>&nbsp;&nbsp;...<BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>如果我们从SQL语句中调用了一个空实例(即SELF为空)的MEMBER方法,方法不会被调用,并且会返回一个空值。如果从过程语句调用的话,PL/SQL就会抛出预定义异常SELEF_IS_NULL。 
                        </P>
                        <UL>
                          <LI>重载 </LI></UL>
                        <P>与打包子程序一样,同种类型的方法(函数或过程)都能被重载。也就是说,我们可以为不同的方法起相同的名字,只要它们的形式参数在数量、顺序或数据类型上有所不同。当我们调用其中一个方法的时候,PL/SQL会把实参列表和形参列表作比较,然后找出合适的方法。</P>
                        <P>子类型也可以重载它的基类方法。这种情况下,方法必须有完全相同的形式参数。</P>
                        <P>如果两个方法只是在参数模式上不同的话,我们是不能进行重载操作的。并且,我们不能因两个函数的返回值类型不同而对它们进行重载。</P>
                        <UL>
                          <LI>MAP和ORDER方法 </LI></UL>
                        <P>一个标量类型,如CHAR或REAL的值都有一个预定义的顺序,这样它们之间就能进行比较。但是对象类型的实例没有预定义的顺序。要想对它们进行比较或排序就要调用我们自己实现的MAP函数。在下面的例子中,关键字MAP指明了方法convert()通过把Relational对象影射到REAL型上,来对它们进行排序操作:</P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>CREATE</STRONG>&nbsp;<STRONG>TYPE</STRONG>&nbsp;rational&nbsp;<STRONG>AS</STRONG>&nbsp;OBJECT(<BR>&nbsp;&nbsp;num&nbsp;&nbsp;&nbsp;<STRONG>INTEGER</STRONG>,<BR>&nbsp;&nbsp;den&nbsp;&nbsp;&nbsp;<STRONG>INTEGER</STRONG>,<BR>&nbsp;&nbsp;MAP&nbsp;MEMBER&nbsp;<STRONG>FUNCTION</STRONG>&nbsp;CONVERT<BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>RETURN</STRONG>&nbsp;<STRONG>REAL</STRONG>,<BR>&nbsp;&nbsp;...<BR>);<BR><BR><STRONG>CREATE</STRONG>&nbsp;<STRONG>TYPE</STRONG>&nbsp;<STRONG>BODY</STRONG>&nbsp;rational&nbsp;<STRONG>AS</STRONG><BR>&nbsp;&nbsp;MAP&nbsp;MEMBER&nbsp;<STRONG>FUNCTION</STRONG>&nbsp;CONVERT<BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>RETURN</STRONG>&nbsp;<STRONG>REAL</STRONG>&nbsp;<STRONG>IS</STRONG><BR>&nbsp;&nbsp;<STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>RETURN</STRONG>&nbsp;num&nbsp;/&nbsp;den;<BR>&nbsp;&nbsp;<STRONG>END</STRONG>&nbsp;CONVERT;<BR>&nbsp;&nbsp;...<BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>PL/SQL使用顺序来计算布尔表达式的值,如x &lt; y,并且可以在DISTINCT,GROUP 
                        BY和ORDER 
                        BY子句中作比较。MAP方法convert()可以返回一个对象在所有Relation对象中的相对位置。</P>
                        <P>一个对象类型只能包含一个MAP方法,它接受一个内置参数SELF并返回一个标量类型:DATE、NUMBER、VARCHAR2,或是一个ANSI 
                        SQL类型,如CHARACTER或REAL。</P>
                        <P>另外,我们还可以用ORDER方法。一个对象类型只能有一个ORDER方法,它必须是一个能返回数字结果的函数。在下面的例子中,关键字ORDER表明了方法match()可以对两个对象进行比较操作:</P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>CREATE</STRONG>&nbsp;<STRONG>TYPE</STRONG>&nbsp;customer&nbsp;<STRONG>AS</STRONG>&nbsp;OBJECT(<BR>&nbsp;&nbsp;ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>NUMBER</STRONG>,<BR>&nbsp;&nbsp;NAME&nbsp;&nbsp;&nbsp;<STRONG>VARCHAR2</STRONG>(20),<BR>&nbsp;&nbsp;addr&nbsp;&nbsp;&nbsp;<STRONG>VARCHAR2</STRONG>(30),<BR>&nbsp;&nbsp;<STRONG>ORDER</STRONG>&nbsp;MEMBER&nbsp;<STRONG>FUNCTION</STRONG>&nbsp;match(c&nbsp;customer)<BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>RETURN</STRONG>&nbsp;<STRONG>INTEGER</STRONG><BR>);<BR><BR><STRONG>CREATE</STRONG>&nbsp;<STRONG>TYPE</STRONG>&nbsp;<STRONG>BODY</STRONG>&nbsp;customer&nbsp;<STRONG>AS</STRONG><BR>&nbsp;&nbsp;<STRONG>ORDER</STRONG>&nbsp;MEMBER&nbsp;<STRONG>FUNCTION</STRONG>&nbsp;match(c&nbsp;customer)<BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>RETURN</STRONG>&nbsp;<STRONG>INTEGER</STRONG>&nbsp;<STRONG>IS</STRONG><BR>&nbsp;&nbsp;<STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>IF</STRONG>&nbsp;ID&nbsp;&lt;&nbsp;c.ID&nbsp;<STRONG>THEN</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>RETURN</STRONG>&nbsp;-1;&nbsp;&nbsp;&nbsp;<EM>--&nbsp;any&nbsp;negative&nbsp;number&nbsp;will&nbsp;do</EM><BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>ELSIF</STRONG>&nbsp;ID&nbsp;&gt;&nbsp;c.ID&nbsp;<STRONG>THEN</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>RETURN</STRONG>&nbsp;1;&nbsp;&nbsp;&nbsp;<EM>--&nbsp;any&nbsp;positive&nbsp;number&nbsp;will&nbsp;do</EM><BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>ELSE</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>RETURN</STRONG>&nbsp;0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>END</STRONG>&nbsp;<STRONG>IF</STRONG>;<BR>&nbsp;&nbsp;<STRONG>END</STRONG>;<BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>每个ORDER方法都只能接受两个参数:内置参数SELF和另外一个同类型的对象。如果c1和c2是Customer对象,一个c1 
                        &gt; 
                        c2这样的比较就会自动调用方法match。该方法能够返回负数、零或正数,分别代表SELF比另外一个对象小、等或大。如果传到ORDER方法的参数任意一个为空,方法就会返回空值。</P>
                        <P>知道方针:一个MAP方法就好比一个哈希函数,能把对象值影射到标量值,然后用操作符,如&lt;、=等来进行比较。一个ORDER方法只是简单地将两个对象进行比较。</P>
                        <P>我们可以声明一个MAP方法或是一个ORDER方法,但不同时声明这两个方法。如果我们声明了其中一个,我们就可以在SQL或过程语句中进行对象比较。但是,如果我们没有声明方法,我们就只能在SQL语句中进行等或不等的比较。(两个同类型的对象只有它们对应的属性值相同的时候才相等。)</P>
                        <P>在对大量的对象进行排序或合并的时候,可以使用一个MAP方法。一次调用会把所有的对象影射到标量中,然后对标量值进行排序。ORDER方法的效率相对比较低,因为它必须反复地调用(它一次只能比较两个对象)。</P>
                        <UL>
                          <LI>构造方法 </LI></UL>
                        <P>每个对象类型都有一个构造方法,它是一个名称与对象类型名称相同的函数,用于初始化,并能返回一个对象类型的新的实例。</P>
                        <P>Oracle会为每个对象类型生成一个构造函数,其中形参与对象类型的属性相匹配。也就是说,参数和属性是一一对应的关系,并且顺序、名称和数据类型都完全相同。</P>
                        <P>我们也可以定义自己的构造方法,要么覆盖掉系统定义的构造函数,要么定义一个有着不同方法签名的新构造函数。</P>
                        <P>PL/SQL从来不会隐式地调用构造函数,所以我们必须显式地调用它。</P>
                        <P class=title2>3、更改已存在对象类型的属性和方法</P>
                        <P>我们可以使用ALTER TYPE语句来添加、修改或删除属性,并可以为已存在的对象类型添加或删除方法: 
                        </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>CREATE</STRONG>&nbsp;<STRONG>TYPE</STRONG>&nbsp;person_typ&nbsp;<STRONG>AS</STRONG>&nbsp;OBJECT(<BR>&nbsp;&nbsp;NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>CHAR</STRONG>(20),<BR>&nbsp;&nbsp;ssn&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>CHAR</STRONG>(12),<BR>&nbsp;&nbsp;address&nbsp;&nbsp;&nbsp;<STRONG>VARCHAR2</STRONG>(100)<BR>);<BR><BR><STRONG>CREATE</STRONG>&nbsp;<STRONG>TYPE</STRONG>&nbsp;person_nt&nbsp;<STRONG>IS</STRONG>&nbsp;<STRONG>TABLE</STRONG>&nbsp;<STRONG>OF</STRONG>&nbsp;person_typ;<BR><BR><STRONG>CREATE</STRONG>&nbsp;<STRONG>TYPE</STRONG>&nbsp;dept_typ&nbsp;<STRONG>AS</STRONG>&nbsp;OBJECT(<BR>&nbsp;&nbsp;mgr&nbsp;&nbsp;&nbsp;&nbsp;person_typ,<BR>&nbsp;&nbsp;emps&nbsp;&nbsp;&nbsp;person_nt<BR>);<BR><BR><STRONG>CREATE</STRONG>&nbsp;&nbsp;<STRONG>TABLE</STRONG>&nbsp;dept&nbsp;<STRONG>OF</STRONG>&nbsp;dept_typ;<BR><EM>--&nbsp;Add&nbsp;new&nbsp;attributes&nbsp;to&nbsp;Person_typ&nbsp;and&nbsp;propagate&nbsp;the&nbsp;change</EM><BR><EM>--&nbsp;to&nbsp;Person_nt&nbsp;and&nbsp;dept_typ</EM><BR><STRONG>ALTER</STRONG>&nbsp;&nbsp;<STRONG>TYPE</STRONG>&nbsp;person_typ&nbsp;ADD&nbsp;ATTRIBUTE&nbsp;(picture&nbsp;BLOB,&nbsp;dob&nbsp;<STRONG>DATE</STRONG>)<BR>&nbsp;&nbsp;CASCADE&nbsp;<STRONG>NOT</STRONG>&nbsp;INCLUDING&nbsp;<STRONG>TABLE</STRONG>&nbsp;DATA;<BR><BR><STRONG>CREATE</STRONG>&nbsp;<STRONG>TYPE</STRONG>&nbsp;mytype&nbsp;<STRONG>AS</STRONG>&nbsp;OBJECT(<BR>&nbsp;&nbsp;attr1&nbsp;&nbsp;&nbsp;<STRONG>NUMBER</STRONG>,<BR>&nbsp;&nbsp;attr2&nbsp;&nbsp;&nbsp;<STRONG>NUMBER</STRONG><BR>);<BR><BR><STRONG>ALTER</STRONG>&nbsp;&nbsp;<STRONG>TYPE</STRONG>&nbsp;mytype&nbsp;ADD&nbsp;ATTRIBUTE&nbsp;(attr3&nbsp;<STRONG>NUMBER</STRONG>),<BR>&nbsp;&nbsp;<STRONG>DROP</STRONG>&nbsp;ATTRIBUTE&nbsp;attr2,<BR>&nbsp;&nbsp;ADD&nbsp;ATTRIBUTE&nbsp;attr4&nbsp;<STRONG>NUMBER</STRONG>&nbsp;CASCADE; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>在过程编译时,它总是使用当前引用的对象类型版本。在对象类型发生改变时,服务器端引用那个对象类型的过程就变得无效了,在下次过程被调用时它会被自动重新编译。而对于客户端引用被更改过的类型的过程,我们就必须手动编译。 
                        </P>
                        <P>如果从基类删除一个方法,那么也必须修改覆盖被删除方法的子类。我们可以用ALTER 
                        TYPE的CASADE选择来判断是否有子类被影响到;如果有子类覆盖了方法,那么语句就会被回滚。为了能成功地从基类删除一个方法,我们可以: 
                        </P>
                        <OL>
                          <LI>先从子类删除方法 
                          <LI>从基类删除方法,然后用不带OVERRIDING关键字的ALTER TYPE把它重新添加进去 
                        </LI></OL>
                        <P class=title1>六、定义对象类型</P>
                        <P>对象类型可以表现现实世界中的任何实体。例如,一个对象类型能表现学生,银行账户,计算机显示器,有理数或者是像队列,栈,链表这样的数据结构。这一节给出了几个完整的例子,让我们了解如何设计对象类型并编写我们自己的对象类型。</P>
                        <P>目前我们还不能在PL/SQL块、子程序或包中定义对象类型。但是,我们可以在SQL*Plus中用下面的语法来定义它: 
                        </P>
                        <BLOCKQUOTE>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -