📄 第二章 pl-sql基础 - pl-sql用户指南与参考 - whatiswhat.htm
字号:
</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap>my_dname scott.dept.dname%<STRONG>TYPE</STRONG>;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>使用%TYPE声明my_dname有两个好处。首先,我们不必知道dname具体的数据类型。其次,如果数据库中对dname的数据类型定义发生了改变,变量my_dname的数据类型也会在运行时作出相应的改变。但是要注意的是,%TYPE只提供类型信息,并不提供NOT
NULL约束信息,所以下面这段代码即时是在emp.empno不可为空的情况下也是可以运行的: </P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>DECLARE</STRONG><BR> my_empno emp.empno%<STRONG>TYPE</STRONG>;<BR> ...<BR><STRONG>BEGIN</STRONG><BR> my_empno := <STRONG>NULL</STRONG>; <EM>-- tdis works</EM>
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P class=title2>4、使用%ROWTYPE</P>
<P>%ROWTYPE属性提供数据表(或视图)中一整行数据的类型信息。记录可以完整地保存从游标或游标变量中取出的当前行的信息。下面例子中,我们声明了两个记录,第一个保存emp表的行信息,第二个保存从游标c1取出的行信息。
</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>DECLARE</STRONG><BR> emp_rec emp%<STRONG>ROWTYPE</STRONG>;<BR> <STRONG>CURSOR</STRONG> c1 <STRONG>IS</STRONG> <STRONG><BR> SELECT</STRONG> deptno, dname, loc <STRONG>FROM</STRONG> dept;<BR> dept_rec c1%<STRONG>ROWTYPE</STRONG>;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>我们还可以为指定的域进行赋值操作,如下例:</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap>emp_rec.ename := <EM>'JOHNSON'</EM>;<BR>emp_rec.sal := emp_rec.sal * 1.15;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>%ROWTYPE同%TYPE一样,只提供类型信息,并不能保证NOT
NULL约束。在最后一个例子中,我们使用%ROWTYPE来定义一个打包游标(packaged cursor):
</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>CREATE</STRONG> <STRONG>PACKAGE</STRONG> emp_actions <STRONG>AS</STRONG><BR> <STRONG>CURSOR</STRONG> c1 <STRONG>RETURN</STRONG> emp%<STRONG>ROWTYPE</STRONG>; <EM>-- declare cursor specification</EM><BR> ...<BR><STRONG>END</STRONG> emp_actions;<BR><STRONG>CREATE</STRONG> <STRONG>PACKAGE</STRONG> <STRONG>BODY</STRONG> emp_actions <STRONG>AS</STRONG><BR> <STRONG>CURSOR</STRONG> c1 <STRONG>RETURN</STRONG> emp%<STRONG>ROWTYPE</STRONG> <STRONG>IS</STRONG> <EM>-- define cursor body</EM><BR> <STRONG>SELECT</STRONG> * <STRONG>FROM</STRONG> emp <STRONG>WHERE</STRONG> sal > 3000;<BR> ...<BR><STRONG>END</STRONG> emp_actions;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<UL>
<LI>聚合赋值 </LI></UL>
<P>用%ROWTYPE作声明的时候是不可以进行初始化赋值的,但是有两种方法可以一次性为所有字段赋值。方法一:假如两个记录类型的声明引用了同一数据表或游标,那么它们就可以相互赋值,如:</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>DECLARE</STRONG><BR> dept_rec1 dept%<STRONG>ROWTYPE</STRONG>;<BR> dept_rec2 dept%<STRONG>ROWTYPE</STRONG>;<BR> <STRONG>CURSOR</STRONG> c1 <STRONG>IS</STRONG> <STRONG><BR> SELECT</STRONG> deptno, dname, loc <STRONG> FROM</STRONG> dept;<BR> dept_rec3 c1%<STRONG>ROWTYPE</STRONG>;<BR><STRONG>BEGIN</STRONG><BR> ...<BR> dept_rec1 := dept_rec2;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>但是,如果一个类型是引用的是数据表而另一个引用的是游标的话,那么,即使它们表现的内容相同,也是不能相互赋值的:</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap>dept_rec2 := dept_rec3; <EM>-- not allowed</EM>
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>方法二:我们可以使用SELECT或FETCH语句将取得的数据赋给记录。但在表或视图中定义的字段名称顺序要与记录中的名称顺序相同。
</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>DECLARE</STRONG><BR> dept_rec dept%<STRONG>ROWTYPE</STRONG>;<BR> ...<BR><STRONG>BEGIN</STRONG><BR> <STRONG>SELECT</STRONG> * <STRONG>INTO</STRONG> dept_rec <STRONG>FROM</STRONG> dept <STRONG>WHERE</STRONG> deptno = 30;<BR> ...<BR><STRONG>END</STRONG>;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>但是,我们不能使用赋值语句来把字段列表中的值赋给记录。所以,下面的语法形式是不允许的:</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap>record_name := (value1, value2, value3, ...); <EM>-- not allowed</EM>
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<UL>
<LI>使用别名 </LI></UL>
<P>从游标中取出的数据,如果游标定义中含有表达式时,我们就需要使用别名才能正确地为%ROWTYPE类型记录赋值:
</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>DECLARE</STRONG><BR> <STRONG>CURSOR</STRONG> my_cursor <STRONG>IS</STRONG><BR> <STRONG>SELECT</STRONG> sal + NVL(comm, 0) wages, ename <STRONG>FROM</STRONG> emp;<BR> my_rec my_cursor%<STRONG>ROWTYPE</STRONG>;<BR><STRONG>BEGIN</STRONG><BR> <STRONG>OPEN</STRONG> my_cursor;<BR> <STRONG>LOOP</STRONG><BR> <STRONG>FETCH</STRONG> my_cursor <STRONG>INTO</STRONG> my_rec;<BR> <STRONG>EXIT</STRONG> <STRONG>WHEN</STRONG> my_cursor%NOTFOUND;<BR> <STRONG>IF</STRONG> my_rec.wages > 2000 <STRONG>tdEN</STRONG><BR> <STRONG>INSERT</STRONG> <STRONG>INTO</STRONG> temp <STRONG>VALUES</STRONG> (<STRONG>NULL</STRONG>, my_rec.wages, my_rec.ename);<BR> <STRONG>END</STRONG> <STRONG>IF</STRONG>;<BR> <STRONG>END</STRONG> <STRONG>LOOP</STRONG>;<BR> <STRONG>CLOSE</STRONG> my_cursor;<BR><STRONG>END</STRONG>;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P class=title2>5、声明的约束</P>
<P>PL/SQL不允许向前引用。也就是说我们在使用变量或常量之前必须先声明。像下面这样的语句就是不合法的:
</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap>maxi <STRONG>INTEGER</STRONG> := 2 * mini; <EM>-- not allowed</EM><BR>mini <STRONG>INTEGER</STRONG> := 15;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>但是,PL/SQL允许向前声明子程序。 </P>
<P>对于同样数据类型的每一个变量,都必须单独声明: </P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap>i <STRONG>SMALLINT</STRONG>;<BR>j <STRONG>SMALLINT</STRONG>;<BR>k <STRONG>SMALLINT</STRONG>;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>像下面这样的声明方式是不允许的: </P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap>i, j, k <STRONG>SMALLINT</STRONG>; <EM>-- not allowed</EM>
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P class=title1>四、PL/SQL命名规范</P>
<P>同样的命名规约适用于所有的PL/SQL程序,规约涉及的内容包括常量、变量、游标、异常、过程、函数和包。命名可能是简单的,加以限定的,远程的或是既加以限定又是远程的。例如,我们也许可能用到以下几种调用过程raise_salary的方式:
</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap>raise_salary(...); <EM>-- simple</EM><BR>emp_actions.raise_salary(...); <EM>-- qualified</EM><BR>raise_salary@newyork(...); <EM>-- remote</EM><BR>emp_actions.raise_salary@newyork(...); <EM>-- qualified and remote</EM>
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>第一种情况,我们只是简单的使用程序名称。第二种情况,我们必须使用点标志(dot
notation)来引用过程,因为它是保存在emp_actions包中的。第三种情况,使用远程访问指示符,就能引用数据库连接newyork,因为过程是存放在远程数据库的。第四中情况,我们在过程名称加上限定修饰词并引用数据库连接。
</P>
<UL>
<LI>同义词 </LI></UL>
<P>我们可以创建同义词来隐藏远程模式对象的位置,其中包括表、视图、序列、存储函数、包、和对象类型。但是,我们不能为子程序或包中声明的内容创建同义词,其中包括常量、变量、游标变量、异常和打包子程序。
</P>
<UL>
<LI>作用域 </LI></UL>
<P>同一作用域内声明的标识符都必须是唯一的。所以,即使它们的数据类型不同,变量和参数也不能享用同一名称。下例中,第二个声明是不允许的:</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap>valid_id <STRONG>BOOLEAN</STRONG>;<BR>valid_id <STRONG>VARCHAR2</STRONG> (5); <EM>-- not allowed duplicate identifier</EM>
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<UL>
<LI>大小写敏感 </LI></UL>
<P>像所有的标识符一样,常量、变量和参数的名称都是大小写不敏感的。例如,PL/SQL认为下面的名称都是相同的:
</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap>zip_code <STRONG>INTEGER</STRONG>;<BR>zip_code <STRONG>INTEGER</STRONG>; <EM>-- same as zip_code</EM>
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<UL>
<LI>命名解析 </LI></UL>
<P>在SQL语句中,数据库字段名称的优先级要高于本地变量和形式参数。例如,下面的DELETE语句会从emp表删除所有的雇员信息,而不只是名字为"KING"的雇员:
</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>DECLARE</STRONG><BR> ename <STRONG>VARCHAR2</STRONG> (10) := <EM>'KING'</EM>;<BR><STRONG>BEGIN</STRONG><BR> <STRONG>DELETE</STRONG> <STRONG>FROM</STRONG> emp<BR> <STRONG>WHERE</STRONG> ename = ename;<BR> ...
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>在这种情况下,为了避免产生歧义,可以像下面这样在本地变量和形式参数的前面加上类似于"my_"这样的前缀:</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>DECLARE</STRONG><BR> my_ename <STRONG>VARCHAR2</STRONG>(10);
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>或是使用块标签来进行引用限定: </P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><<main>><BR><STRONG>DECLARE</STRONG><BR> ename <STRONG>VARCHAR2</STRONG> (10) := <EM>'KING'</EM>;<BR><STRONG>BEGIN</STRONG><BR> <STRONG>DELETE</STRONG> <STRONG>FROM</STRONG> emp<BR> <STRONG>WHERE</STRONG> ename = main.ename;<BR> ...
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>下面的例子演示了如何使用子程序名称来限定对本地变量和形式参数的引
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -