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

📄 第十一章 本地动态sql - pl-sql用户指南与参考 - whatiswhat.htm

📁 sql初学者不错的教程
💻 HTM
📖 第 1 页 / 共 5 页
字号:
                              <TD 
                                noWrap><STRONG>DECLARE</STRONG><BR>&nbsp;&nbsp;<STRONG>TYPE</STRONG>&nbsp;namelist&nbsp;<STRONG>IS</STRONG>&nbsp;<STRONG>TABLE</STRONG>&nbsp;<STRONG>OF</STRONG>&nbsp;<STRONG>VARCHAR2</STRONG>(15);<BR><BR>&nbsp;&nbsp;enames&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;namelist;<BR>&nbsp;&nbsp;bonus_amt&nbsp;&nbsp;&nbsp;<STRONG>NUMBER</STRONG>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:=&nbsp;500;<BR>&nbsp;&nbsp;sql_stmt&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>VARCHAR</STRONG>(200);<BR><STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;sql_stmt&nbsp;&nbsp;&nbsp;&nbsp;:=&nbsp;<EM>'UPDATE&nbsp;emp&nbsp;SET&nbsp;bonus&nbsp;=&nbsp;:1&nbsp;RETURNING&nbsp;ename&nbsp;INTO&nbsp;:2'</EM>;<BR><BR>&nbsp;&nbsp;<STRONG>EXECUTE</STRONG>&nbsp;<STRONG>IMMEDIATE</STRONG>&nbsp;sql_stmt<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;USING&nbsp;bonus_amt<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURNING&nbsp;<STRONG>BULK</STRONG>&nbsp;<STRONG>COLLECT</STRONG>&nbsp;<STRONG>INTO</STRONG>&nbsp;enames;<BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>要在SQL语句中绑定输入参数,就要使用FORALL语句和USING子句,但这时的SQL语句不能是查询语句,如下例: 
                        </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>DECLARE</STRONG><BR>&nbsp;&nbsp;<STRONG>TYPE</STRONG>&nbsp;numlist&nbsp;<STRONG>IS</STRONG>&nbsp;<STRONG>TABLE</STRONG>&nbsp;<STRONG>OF</STRONG>&nbsp;<STRONG>NUMBER</STRONG>;<BR><BR>&nbsp;&nbsp;<STRONG>TYPE</STRONG>&nbsp;namelist&nbsp;<STRONG>IS</STRONG>&nbsp;<STRONG>TABLE</STRONG>&nbsp;<STRONG>OF</STRONG>&nbsp;<STRONG>VARCHAR2</STRONG>(15);<BR><BR>&nbsp;&nbsp;empnos&nbsp;&nbsp;&nbsp;numlist;<BR>&nbsp;&nbsp;enames&nbsp;&nbsp;&nbsp;namelist;<BR><STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;empnos&nbsp;&nbsp;&nbsp;&nbsp;:=&nbsp;numlist(1,&nbsp;2,&nbsp;3,&nbsp;4,&nbsp;5);<BR>&nbsp;&nbsp;<STRONG>FORALL</STRONG>&nbsp;i&nbsp;<STRONG>IN</STRONG>&nbsp;1&nbsp;..&nbsp;5<BR>&nbsp;&nbsp;&nbsp;&nbsp;<STRONG>EXECUTE</STRONG>&nbsp;<STRONG>IMMEDIATE</STRONG>&nbsp;<EM>'UPDATE&nbsp;emp&nbsp;SET&nbsp;sal&nbsp;=&nbsp;sal&nbsp;*&nbsp;1.1&nbsp;WHERE&nbsp;empno&nbsp;=&nbsp;:1&nbsp;'</EM>&nbsp;||<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<EM>'RETURNING&nbsp;ename&nbsp;INTO&nbsp;:2'</EM><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;USING&nbsp;empnos(i)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURNING&nbsp;<STRONG>BULK</STRONG>&nbsp;<STRONG>COLLECT</STRONG>&nbsp;<STRONG>INTO</STRONG>&nbsp;enames;<BR>&nbsp;&nbsp;...<BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P class=title1>六、动态SQL的技巧与陷阱</P>
                        <P>这节会让我们了解如何完全利用动态SQL语句并避免一些常见的缺陷。 </P>
                        <P class=title2>1、改善性能</P>
                        <P>下例中,Oracle为每个不同的emp_id单独打开一个游标。这就造成资源浪费并降低了效率: </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>CREATE</STRONG>&nbsp;<STRONG>PROCEDURE</STRONG>&nbsp;fire_employee(emp_id&nbsp;<STRONG>NUMBER</STRONG>)&nbsp;<STRONG>AS</STRONG><BR><STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;<STRONG>EXECUTE</STRONG>&nbsp;<STRONG>IMMEDIATE</STRONG>&nbsp;<EM>'DELETE&nbsp;FROM&nbsp;emp&nbsp;WHERE&nbsp;empno&nbsp;=&nbsp;'</EM>&nbsp;||&nbsp;TO_CHAR(emp_id);<BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>我们可以使用绑定变量来改善性能,如下例所示。这就能让Oracle为不同的emp_id值重用同一个游标。 
                        </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>CREATE</STRONG>&nbsp;<STRONG>PROCEDURE</STRONG>&nbsp;fire_employee(emp_id&nbsp;<STRONG>NUMBER</STRONG>)&nbsp;<STRONG>AS</STRONG><BR><STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;<STRONG>EXECUTE</STRONG>&nbsp;<STRONG>IMMEDIATE</STRONG>&nbsp;<EM>'DELETE&nbsp;FROM&nbsp;emp&nbsp;WHERE&nbsp;empno&nbsp;=&nbsp;:num'</EM><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;USING&nbsp;emp_id;<BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P class=title2>2、让过程对任意模式对象起作用</P>
                        <P>假设我们需要一个过程,让它接受数据表名,然后将指定的表从数据库中删除。我们可能会下面这样编写使用动态SQL的独立过程: 
                        </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>CREATE</STRONG>&nbsp;<STRONG>PROCEDURE</STRONG>&nbsp;drop_table(table_name&nbsp;<STRONG>IN</STRONG>&nbsp;<STRONG>VARCHAR2</STRONG>)&nbsp;<STRONG>AS</STRONG><BR><STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;<STRONG>EXECUTE</STRONG>&nbsp;<STRONG>IMMEDIATE</STRONG>&nbsp;<EM>'DROP&nbsp;TABLE&nbsp;:tab'</EM><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;USING&nbsp;table_name;<BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>但是,在运行的时候,这个过程可能会因为表名错误而无法执行成功。这就是我们为什么不能用参数绑定来为动态SQL传递模式对象的名称。解决方法是直接把参数嵌套到字符串中。我们把上面的EXECUTE 
                        IMMEDIATE语句修改一下: </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>CREATE</STRONG>&nbsp;<STRONG>PROCEDURE</STRONG>&nbsp;drop_table(table_name&nbsp;<STRONG>IN</STRONG>&nbsp;<STRONG>VARCHAR2</STRONG>)&nbsp;<STRONG>AS</STRONG><BR><STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;<STRONG>EXECUTE</STRONG>&nbsp;<STRONG>IMMEDIATE</STRONG>&nbsp;<EM>'<STRONG>DROP</STRONG>&nbsp;<STRONG>TABLE</STRONG>&nbsp;'</EM>&nbsp;||&nbsp;table_name;<BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>这样,我们就可以向动态SQL语句传递任意数据表名称了。 </P>
                        <P class=title2>3、使用重复占位符</P>
                        <P>动态SQL语句中的占位符与USING子句中的绑定参数是位置关联的,而不是名称关联。所以,如果在SQL语句中同样的占位符出现两次或多次,那么,它的每次出现都必须与一个USING子句中的绑定参数相关联。例如下面的动态字符串: 
                        </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap>sql_stmt&nbsp;:=&nbsp;<EM>'INSERT&nbsp;INTO&nbsp;payroll&nbsp;VALUES&nbsp;(:x,&nbsp;:x,&nbsp;:y,&nbsp;:x)'</EM>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>我们可以为动态字符串编写对应的USING子句: </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>EXECUTE</STRONG>&nbsp;<STRONG>IMMEDIATE</STRONG>&nbsp;sql_stmt&nbsp;USING&nbsp;a,&nbsp;a,&nbsp;b,&nbsp;a; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>但是,动态PL/SQL块中只有唯一的占位符才与USING子句中的绑定参数按位置对应。所以,如果一个占位符在PL/SQL块中出现两次或多次,那么所有这样相同的占位符都只与USING语句中的一个绑定参数相对应。比如下面的例子,第一个占位符(x)与第一个绑定参数(a)关联,第二个占位符 
                        (y)与第二个绑定参数(b)关联。 </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>DECLARE</STRONG><BR>&nbsp;&nbsp;a&nbsp;&nbsp;&nbsp;<STRONG>NUMBER</STRONG>&nbsp;:=&nbsp;4;<BR>&nbsp;&nbsp;b&nbsp;&nbsp;&nbsp;<STRONG>NUMBER</STRONG>&nbsp;:=&nbsp;7;<BR><STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;plsql_block&nbsp;&nbsp;&nbsp;&nbsp;:=&nbsp;<EM>'BEGIN&nbsp;calc_stats(:x,&nbsp;:x,&nbsp;:y,&nbsp;:x);&nbsp;END'</EM>;<BR><BR>&nbsp;&nbsp;<STRONG>EXECUTE</STRONG>&nbsp;<STRONG>IMMEDIATE</STRONG>&nbsp;plsql_block<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;USING&nbsp;a,&nbsp;b;<BR>&nbsp;&nbsp;...<BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P class=title2>4、使用游标属性</P>
                        <P>每个显式的游标都有四个属性:%FOUND、%ISOPEN、%NOTFOUND和%ROWCOUNT。它们都能返回与静态或动态SQL语句执行结果相关的有用信息。 
                        </P>
                        <P>为处理SQL数据操作语句,Oracle会打开一个名为SQL的隐式游标。它的属性会返回最近一次执行的INSERT、UPDATE、DELETE或单行SELECT的相关信息。例如,下面函数就使用%ROWCOUNT返回从数据表中删除的行数: 
                        </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>CREATE</STRONG>&nbsp;<STRONG>FUNCTION</STRONG>&nbsp;rows_deleted(table_name&nbsp;<STRONG>IN</STRONG>&nbsp;<STRONG>VARCHAR2</STRONG>,&nbsp;condition&nbsp;<STRONG>IN</STRONG>&nbsp;<STRONG>VARCHAR2</STRONG>)<BR>&nbsp;&nbsp;<STRONG>RETURN</STRONG>&nbsp;<STRONG>INTEGER</STRONG>&nbsp;<STRONG>AS</STRONG><BR><STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;<STRONG>EXECUTE</STRONG>&nbsp;<STRONG>IMMEDIATE</STRONG>&nbsp;<EM>'DELETE&nbsp;FROM&nbsp;'</EM>&nbsp;||&nbsp;table_name&nbsp;||&nbsp;<EM>'&nbsp;WHERE&nbsp;'</EM>&nbsp;||&nbsp;condition;<BR><BR>&nbsp;&nbsp;<STRONG>RETURN</STRONG>&nbsp;<STRONG>SQL</STRONG>%ROWCOUNT;&nbsp;&nbsp;&nbsp;<EM>--&nbsp;return&nbsp;number&nbsp;of&nbsp;rows&nbsp;deleted</EM><BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>同样,当我们把游标变量的名字附加进去时,游标的属性也能返回多行查询执行结果的相关信息。 </P>
                        <P class=title2>5、传递空值</P>
                        <P>下面,我们来为动态SQL传递空值,见下面的EXECUTE IMMEDIATE语句: </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>EXECUTE</STRONG>&nbsp;<STRONG>IMMEDIATE</STRONG>&nbsp;<EM>'UPDATE&nbsp;emp&nbsp;SET&nbsp;comm&nbsp;=&nbsp;:x'</EM>&nbsp;USING&nbsp;<STRONG>NULL</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>但是,这个语句会因为在USING子句中使用NULL而执行失败,因为USING语句中所传递的参数是不能为空的。所以,要想解决这个问题,直接使用字符串就可以了: 
                        </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>DECLARE</STRONG><BR>&nbsp;&nbsp;a_null&nbsp;&nbsp;&nbsp;<STRONG>CHAR</STRONG>(1);&nbsp;&nbsp;&nbsp;<EM>--&nbsp;set&nbsp;to&nbsp;NULL&nbsp;automatically&nbsp;at&nbsp;run&nbsp;time</EM><BR><STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;<STRONG>EXECUTE</STRONG>&nbsp;<STRONG>IMMEDIATE</STRONG>&nbsp;<EM>'UPDATE&nbsp;emp&nbsp;SET&nbsp;comm&nbsp;=&nbsp;:x'</EM><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;USING&nbsp;a_null;<BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P class=title2>6、远程操作</P>
                        <P>如下例所示,PL/SQL子程序能够执行引用远程数据库对象的动态SQL语句: </P>
                        <BLOCKQUOTE>
                          <TABLE>
                            <TBODY>
                            <TR>
                              <TD 
                                noWrap><STRONG>PROCEDURE</STRONG>&nbsp;delete_dept(db_link&nbsp;<STRONG>VARCHAR2</STRONG>,&nbsp;dept_id&nbsp;<STRONG>INTEGER</STRONG>)&nbsp;<STRONG>IS</STRONG><BR><STRONG>BEGIN</STRONG><BR>&nbsp;&nbsp;<STRONG>EXECUTE</STRONG>&nbsp;<STRONG>IMMEDIATE</STRONG>&nbsp;<EM>'DELETE&nbsp;FROM&nbsp;dept@'</EM>&nbsp;||&nbsp;db_link&nbsp;||&nbsp;<EM>'&nbsp;WHERE&nbsp;deptno&nbsp;=&nbsp;:num'</EM><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;USING&nbsp;dept_id;<BR><STRONG>END</STRONG>; 
                              </TD></TR></TBODY></TABLE></BLOCKQUOTE>
                        <P>同样,远程过程调用(RPC)的目标也包括动态SQL语句。例如,

⌨️ 快捷键说明

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