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

📄 第六章 pl-sql与oracle间交互 - pl-sql用户指南与参考 - whatiswhat.htm

📁 sql初学者不错的教程
💻 HTM
📖 第 1 页 / 共 5 页
字号:
                        <P class=title1>三、用包将游标的声明和游标体分离</P>
                        <P>我们可以将游标说明从游标体中分离出来并放到包中。这样做的话就可以在不改变游标说明的条件下修改游标体。我们可以在包说明中用下面语法编写游标说明: 
                        </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>CURSOR</STRONG>&nbsp;cursor_name&nbsp;[(parameter[,&nbsp;parameter]...)]&nbsp;<STRONG>RETURN</STRONG>&nbsp;return_type; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>在下面的例子中,我们可以使用%ROWTYPE属性来代表数据表emp中的行类型: </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>CREATE</STRONG>&nbsp;<STRONG>PACKAGE</STRONG>&nbsp;emp_stuff&nbsp;<STRONG>AS</STRONG><BR>&nbsp;&nbsp;<STRONG>CURSOR</STRONG>&nbsp;c1&nbsp;<STRONG>RETURN</STRONG>&nbsp;emp%<STRONG>ROWTYPE</STRONG>;&nbsp;&nbsp;&nbsp;<EM>--&nbsp;declare&nbsp;cursor&nbsp;spec</EM><BR>&nbsp;&nbsp;...<BR><STRONG>END</STRONG>&nbsp;emp_stuff;<BR><BR><STRONG>CREATE</STRONG>&nbsp;<STRONG>PACKAGE</STRONG>&nbsp;<STRONG>BODY</STRONG>&nbsp;emp_stuff&nbsp;<STRONG>AS</STRONG><BR>&nbsp;&nbsp;<STRONG>CURSOR</STRONG>&nbsp;c1&nbsp;<STRONG>RETURN</STRONG>&nbsp;emp%<STRONG>ROWTYPE</STRONG>&nbsp;<STRONG>IS</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>SELECT</STRONG>&nbsp;*<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>FROM</STRONG>&nbsp;emp<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>WHERE</STRONG>&nbsp;sal&nbsp;&gt;&nbsp;2500;&nbsp;&nbsp;&nbsp;<EM>--&nbsp;define&nbsp;cursor&nbsp;body</EM><BR>&nbsp;&nbsp;...<BR><STRONG>END</STRONG>&nbsp;emp_stuff; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>游标说明部分并不含有SELECT语句,因为后面RETURN子句中指明了返回值的数据类型。并且,游标体中含有的SELECT语句列表中的每一项,必须和说明部分的RETURN子句相匹配。</P>
                        <P>打包游标有着更好的灵活性。例如,我们可以任意修改上例中声明的游标的游标体而不用修改游标说明: </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>CREATE</STRONG>&nbsp;<STRONG>PACKAGE</STRONG>&nbsp;<STRONG>BODY</STRONG>&nbsp;emp_stuff&nbsp;<STRONG>AS</STRONG><BR>&nbsp;&nbsp;<STRONG>CURSOR</STRONG>&nbsp;c1&nbsp;<STRONG>RETURN</STRONG>&nbsp;emp%<STRONG>ROWTYPE</STRONG>&nbsp;<STRONG>IS</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>SELECT</STRONG>&nbsp;*<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>FROM</STRONG>&nbsp;emp<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>WHERE</STRONG>&nbsp;deptno&nbsp;=&nbsp;20;&nbsp;&nbsp;&nbsp;<EM>--&nbsp;new&nbsp;WHERE&nbsp;clause</EM><BR>&nbsp;&nbsp;...<BR><STRONG>END</STRONG>&nbsp;emp_stuff; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>我们可以使用点标志从一个PL/SQL块或子程序中引用一个打包游标,如下例所示:</P>
                        <P>&nbsp;</P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>DECLARE</STRONG><BR>&nbsp;&nbsp;emp_rec&nbsp;&nbsp;&nbsp;emp%<STRONG>ROWTYPE</STRONG>;<BR>&nbsp;&nbsp;...<BR><STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;...<BR>&nbsp;&nbsp;<STRONG>OPEN</STRONG>&nbsp;emp_stuff.c1;<BR><BR>&nbsp;&nbsp;<STRONG>LOOP</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>FETCH</STRONG>&nbsp;emp_stuff.c1<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>INTO</STRONG>&nbsp;emp_rec;<BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>EXIT</STRONG>&nbsp;<STRONG>WHEN</STRONG>&nbsp;emp_suff.c1%NOTFOUND;<BR>&nbsp;&nbsp;&nbsp;&nbsp;...<BR>&nbsp;&nbsp;<STRONG>END</STRONG>&nbsp;<STRONG>LOOP</STRONG>;<BR><BR>&nbsp;&nbsp;<STRONG>CLOSE</STRONG>&nbsp;emp_stuff.c1;<BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>打包游标的作用域并不局限于某个特定的PL/SQL块。所以,打开一个打包游标后,它会一直保持打开状态直到我们关闭它或是退出Oracle会话。 
                        </P>
                        <P class=title1>四、使用游标FOR循环</P>
                        <P>在大多数需要使用显式游标的情况下,我们都可以用一个游标FOR循环来代替OPEN、FETCH和CLOSE语句。游标FOR循环隐式地声明了一个 
                        %ROWTYPE类型的记录作为它的循环索引,打开游标,然后反复执行把结果集中的行放到索引中去,最后在所有行都被处理完成后关闭游标。</P>
                        <P>思考下面PL/SQL块例子,它能从一个实验中计算出结果,然后把结果保存在一张临时表中。FOR循环的索引c1_rec是被隐式声明的记录。它的每一个域都保存来自游标c1中取出的值。对独立的域的引用可以使用点标志。 
                        </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>DECLARE</STRONG><BR>&nbsp;&nbsp;RESULT&nbsp;&nbsp;&nbsp;temp.col1%<STRONG>TYPE</STRONG>;<BR><BR>&nbsp;&nbsp;<STRONG>CURSOR</STRONG>&nbsp;c1&nbsp;<STRONG>IS</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>SELECT</STRONG>&nbsp;n1,&nbsp;n2,&nbsp;n3<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>FROM</STRONG>&nbsp;data_table<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>WHERE</STRONG>&nbsp;exper_num&nbsp;=&nbsp;1;<BR><STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;<STRONG>FOR</STRONG>&nbsp;c1_rec&nbsp;<STRONG>IN</STRONG>&nbsp;c1&nbsp;<STRONG>LOOP</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;<EM>/*&nbsp;calculate&nbsp;and&nbsp;store&nbsp;the&nbsp;results&nbsp;*/</EM><BR>&nbsp;&nbsp;&nbsp;&nbsp;RESULT&nbsp;&nbsp;:=&nbsp;c1_rec.n2&nbsp;/&nbsp;(c1_rec.n1&nbsp;+&nbsp;c1_rec.n3);<BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>INSERT</STRONG>&nbsp;<STRONG>INTO</STRONG>&nbsp;temp<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>VALUES</STRONG>&nbsp;(RESULT,&nbsp;<STRONG>NULL</STRONG>,&nbsp;<STRONG>NULL</STRONG>);<BR>&nbsp;&nbsp;<STRONG>END</STRONG>&nbsp;<STRONG>LOOP</STRONG>;<BR><BR>&nbsp;&nbsp;<STRONG>COMMIT</STRONG>;<BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>当进入游标FOR循环时后,游标的名称就不属于用OPEN语句打开的游标,也不属于封闭游标FOR循环。在每个循环之前,PL/SQL会把数据放到隐式声明的记录中去。记录的有效作用范围只在循环内,所以我们不能在循环的外部引用它。</P>
                        <P>循环内的语句序列会为每一个满足条件的结果行执行一次,当游标离开循环时,游标会被自动地关闭,这包括正常地使用EXIT或GOTO语句来结束循环,或是因异常抛出而退出循环的情况。 
                        </P>
                        <P class=title2>1、使用子查询代替显式游标</P>
                        <P>有时候我们并不需要声明游标,因为PL/SQL允许我们使用子查询来进行替代。下面的游标FOR循环先计算奖金值,然后把结果插入数据表中: 
                        </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>DECLARE</STRONG><BR>&nbsp;&nbsp;bonus&nbsp;&nbsp;&nbsp;<STRONG>REAL</STRONG>;<BR><STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;<STRONG>FOR</STRONG>&nbsp;emp_rec&nbsp;<STRONG>IN</STRONG>&nbsp;(<STRONG>SELECT</STRONG>&nbsp;empno,&nbsp;sal,&nbsp;comm<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>FROM</STRONG>&nbsp;emp)&nbsp;<STRONG>LOOP</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;bonus&nbsp;&nbsp;:=&nbsp;(emp_rec.sal&nbsp;*&nbsp;0.05)&nbsp;+&nbsp;(emp_rec.comm&nbsp;*&nbsp;0.25);<BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>INSERT</STRONG>&nbsp;<STRONG>INTO</STRONG>&nbsp;bonuses<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>VALUES</STRONG>&nbsp;(emp_rec.empno,&nbsp;bonus);<BR>&nbsp;&nbsp;<STRONG>END</STRONG>&nbsp;<STRONG>LOOP</STRONG>;<BR><BR>&nbsp;&nbsp;<STRONG>COMMIT</STRONG>;<BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P class=title2>2、使用游标子查询</P>
                        <P>我们可以使用游标子查询(又称游标表达式)把一个查询结果集作为参数传递给函数。如下例: </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>SELECT</STRONG>&nbsp;*&nbsp;<STRONG>FROM</STRONG>&nbsp;<STRONG>TABLE</STRONG>(StockPivot(<STRONG>CURSOR</STRONG>(<STRONG>SELECT</STRONG>&nbsp;*&nbsp;<STRONG>FROM</STRONG>&nbsp;StockTable))); 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>游标子查询通常可以用在表函数中,这将在第八章详细讨论。</P>
                        <P class=title2>3、在游标FOR循环中为表达式定义别名</P>
                        <P>隐式声明的记录中每个域存放着最近取得的数据。记录的域名称和SELECT列表中的字段相对应。但是,如果SELECT中含有表达式时会发生什么呢?看一下下面的例子: 
                        </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>CURSOR</STRONG>&nbsp;c1&nbsp;<STRONG>IS</STRONG><BR>&nbsp;&nbsp;<STRONG>SELECT</STRONG>&nbsp;empno,&nbsp;sal&nbsp;+&nbsp;NVL&nbsp;(comm,&nbsp;0)&nbsp;wages,&nbsp;job<BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>FROM</STRONG>&nbsp;... 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>这样的情况下,我们就必须为表达式起一个别名。如下例,wages就是表达式sal+NVL(comm,0)的一个别名:</P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>CURSOR</STRONG>&nbsp;c1&nbsp;<STRONG>IS</STRONG><BR>&nbsp;&nbsp;<STRONG>SELECT</STRONG>&nbsp;empno,&nbsp;sal&nbsp;+&nbsp;NVL&nbsp;(comm,&nbsp;0)&nbsp;wages,&nbsp;job<BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>FROM</STRONG>&nbsp;... 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>如果要引用对应的域,就得使用别名进行代替,如下例所示:</P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>IF</STRONG>&nbsp;emp_rec.wages&nbsp;&lt;&nbsp;1000&nbsp;<STRONG>THEN</STRONG>&nbsp;... 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P class=title2>4、为游标FOR循环传递参数</P>
                        <P>我们可以在游标FOR循环中把参数传递给游标。下例中,我们传递一个部门编号。然后计算出该部门应付给它的雇员的工资数额。并且,我们可以判断出有多少雇员的工资超过2000和/或他们的佣金大于他们的工资。 
                        </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>DECLARE</STRONG><BR>&nbsp;&nbsp;<STRONG>CURSOR</STRONG>&nbsp;emp_cursor&nbsp;(dnum&nbsp;<STRONG>NUMBER</STRONG>)&nbsp;<STRONG>IS</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>SELECT</STRONG>&nbsp;sal,&nbsp;comm<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>FROM</STRONG>&nbsp;emp<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>WHERE</STRONG>&nbsp;deptno&nbsp;=&nbsp;dnum;<BR><BR>&nbsp;&nbsp;total_wages&nbsp;&nbsp;&nbsp;<STRONG>NUMBER</STRONG>&nbsp;(11,&nbsp;2)&nbsp;:=&nbsp;0;<BR>&nbsp;&nbsp;high_paid&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>NUMBER</STRONG>&nbsp;(4)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:=&nbsp;0;<BR>&nbsp;&nbsp;higher_comm&nbsp;&nbsp;&nbsp;<STRONG>NUMBER</STRONG>&nbsp;(4)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:=&nbsp;0;<BR><STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;<EM>/*&nbsp;The&nbsp;number&nbsp;of&nbsp;iterations&nbsp;will&nbsp;equal&nbsp;the&nbsp;number&nbsp;of&nbsp;rows<BR>&nbsp;&nbsp;returned&nbsp;by&nbsp;emp_cursor.&nbsp;*/</EM><BR>&nbsp;&nbsp;<STRONG>FOR</STRONG>&nbsp;emp_record&nbsp;<STRONG>IN</STRONG>&nbsp;emp_cursor&nbsp;(20)&nbsp;<STRONG>LOOP</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;emp_record.comm&nbsp;&nbsp;:=&nbsp;NVL&nbsp;(emp_record.comm,&nbsp;0);<BR>&nbsp;&nbsp;&nbsp;&nbsp;total_wages&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:=&nbsp;total_wages&nbsp;+&nbsp;emp_record.sal&nbsp;+&nbsp;emp_record.comm;<BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>IF</STRONG>&nbsp;emp_record.sal&nbsp;&gt;&nbsp;2000.00&nbsp;<STRONG>THEN</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;high_paid&nbsp;&nbsp;:=&nbsp;high_paid&nbsp;+&nbsp;1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>END</STRONG>&nbsp;<STRONG>IF</STRONG>;<BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>IF</STRONG>&nbsp;emp_record.comm&nbsp;&gt;&nbsp;emp_record.sal&nbsp;<STRONG>THEN</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;higher_comm&nbsp;&nbsp;:=&nbsp;higher_comm&nbsp;+&nbsp;1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>END</STRONG>&nbsp;<STRONG>IF</STRONG>;<BR>&nbsp;&nbsp;<STRONG>END</STRONG>&nbsp;<STRONG>LOOP</STRONG>;<BR><BR>&nbsp;&nbsp;<STRONG>INSERT</STRONG>&nbsp;<STRONG>INTO</STRONG>&nbsp;temp<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>VALUES</STRONG>&nbsp;(high_paid,&nbsp;higher_comm,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<EM>'Total&nbsp;Wages:&nbsp;'</EM>&nbsp;||&nbsp;TO_CHAR&nbsp;(total_wages));<BR>&nbsp;&nbsp;<STRONG>COMMIT</STRONG>;<BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P class=title1>五、使用游标变量</P>
                        <P>跟游标一样,游标变量也是指向多行查询的结果集中的当前行。但是,游标与游标变量不同之处就和常量与变量不同之处类似。游标是静态的,而游标变量是动态的,因为游标变量并不与某个特定的查询相绑定。所以,游标变量可以打开任何类型兼容的查询,灵活性很大。 
                        </P>
                        <P>并且,我们还可以为游标变量赋新值,把它作为参数传递给本地和存储子程序。这就很容易地让我们把数据检索集中化处理。 
                        </P>
                        <P>游标变量可以在每个PL/SQL客户端使用。例如,我们可以在OCI或Pro*C这样的主环境中声明游标变量,然后把它作为输入主变量(绑定变量) 
                        传给PL/SQL。并且,像Oracle Forms和Oracle 
                        Reports这样的含有PL/SQL引擎的开发工具,完全可以在客户端使用游标变量。Oracle服务器也有一个PL/SQL引擎。所以,我们可以在应用程序和服务器之间通过远程调用(RPC)来回传递游标变量。 
                        </P>
                        <P class=title2>1、什么是游标变量</P>
                        <P>游标变量同C或Pascal语言中的指针类似,它指向一块内存地址,而不是地址中的内容本身。所以,声明一个游标变量可以创建一个指针,而不是具体的内容。在PL/SQL中,指针是一个REF 
                        X类型,REF是REFERENCE的缩写,而X代表对象的类型。因此,游标变量的数据类型是REF CURSOR。 
                        </P>
                        <P>为了执行多行查询,Oracle会开启一个未命名的工作区来存放处理信息。我们可以用显式游标为工作区命名然后访问相关的信息;或者声明指向工作区的一个游标变量。无论在什么地方使用游标,它总是指向同一个查询工作区,而游标变量则可以指向不同的工作区。所以,游标和游标变量不能交互使用;也就是说,我们不能在该使用游标的地方使用游标变量,不能在该使用游标变量的地方使用游标。 
                        </P>
                        <P class=title2>2、为什么使用游标变量</P>
                        <P>我们主要是在PL/SQL存储子程序和各种客户端之间用游标变量来传递查询结果。PL/SQL和其他客户端程序都不拥有结果集,它们只是共享一个指向存放结果集工作区的指针而已。例如,一个OCI客户端,一个Oracle 
                        Forms应用程序和Oracle服务器可以引用同一个工作区。 </P>
                        <P>只要有游标变量指向查询工作区,我们就可以引用它。因此,我们可以把游标变量的值自由地从一个作用域传递到另一个。例如,我们把主游标变量传递到嵌套在Pro*C程序中的PL/SQL块,游标变量指向的工作区就可以被访问。 
                        </P>
                        <P>如果客户端含有PL/SQL引擎,那么从客户端调用服务器端就不会有什么约束。假如我们在客户端声明游标变量,在服务器端打开并取得数据,然后把取得的结果返回给客户端。这些操作都是在服务器端完成,从而也减少了网络流量。 
                        </P>
                      

⌨️ 快捷键说明

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