【转】Oracle 执行动态语句

1.静态SQLSQL与动态SQL
Oracle编译PL/SQL程序块分为两个种:其一为前期联编(early binding),即SQL语句在程序编译期间就已经确定,大多数的编译情况属于这种类型;另外一种是后期联编(late binding),即SQL语句只有在运行阶段才能建立,例如当查询条件为用户输入时,那么Oracle的SQL引擎就无法在编译期对该程序语句进行确定,只能在用户输入一定的查询条件后才能提交给SQL引擎进行处理。通常,静态SQL采用前一种编译方式,而动态SQL采用后一种编译方式。

2.动态SQL程序开发
理解了动态SQL编译的原理,也就掌握了其基本的开发思想。动态SQL既然是一种”不确定”的SQL,那其执行就有其相应的特点。Oracle中提供了Execute immediate语句来执行动态SQL,语法如下:

Excute immediate 动态SQL语句 using 绑定参数列表 returning into 输出参数列表;

1)动态SQL是指DDL和不确定的DML(即带参数的DML)
2)绑定参数列表为输入参数列表,即其类型为in类型,在运行时刻与动态SQL语句中的参数(实际上占位符,可以理解为函数里面的形式参数)进行绑定。
3)输出参数列表为动态SQL语句执行后返回的参数列表。
4)由于动态SQL是在运行时刻进行确定的,所以相对于静态而言,其更多的会损失一些系统性能来换取其灵活性。

设数据库的emp表,其数据为如下:

ID NAME SALARY
100 Jacky 5600
101 Rose 3000
102 John 4500

要求
1.创建该表并输入相应的数据。
2.根据特定ID可以查询到其姓名和薪水的信息。
3.根据大于特定的薪水的查询相应的员工信息。
根据前面的要求,可以分别创建三个过程(均使用动态SQL)来实现:
过程一

 1 create or replace procedure create_table is
 2 begin
 3 execute immediate ‘ create table emp(
 4 id number,
 5 name varchar2(10),
 6 salary number )‘; --动态SQL为DDL语句  7 end create_table;

过程二

 1 create or replace procedure find_info(p_id number) is
 2 v_name varchar2(10);
 3 v_salary number;
 4 begin
 5 execute immediate ‘
 6 select name,salary from emp
 7 where id=:1‘
 8 using p_id
 9 returning into v_name,v_salary; --动态SQL为查询语句
10 dbms_output.put_line(v_name ||‘的收入为:‘||to_char(v_salary));
11 exception
12 when others then
13 dbms_output.put_line(‘找不到相应数据‘);
14 end find_info;

过程三

 1 create or replace procedure find_emp(p_salary number) is
 2 r_emp emp%rowtype;
 3 type c_type is ref cursor;
 4 c1 c_type;
 5 begin
 6 open c1 for ‘
 7 select * from emp
 8 where salary >:1‘
 9 using p_salary;
10 loop
11 fetch c1 into r_emp;
12 exit when c1%notfound;
13 dbms_output.put_line(‘薪水大于‘||to_char(p_salary)||‘的员工为:‘);
14 dbms_output.put_line(‘ID为‘to_char(r_emp)||‘ 其姓名为:‘||r_emp.name);
15 end loop;
16 close c1;
17 end create_table;

注意:在过程二中的动态SQL语句使用了占位符“:1“,其实它相当于函数的形式参数,使用”:“作为前缀,然后使用using语句将p_id在运行时刻将:1给替换掉,这里p_id相当于函数里的实参。另外过程三中打开的游标为动态游标,它也属于动态SQL的范畴,其整个编译和开发的过程与execute immediate执行的过程很类似,这里就不在赘述了。
3. 动态SQL语句开发技巧
前面分析到了,动态SQL的执行是以损失系统性能来换取其灵活性的,所以对它进行一定程度的优化也是必要的,笔者根据实际开发经验给出一些开发的技巧,需要指出的是,这里很多经验不仅局限于动态SQL,有些也适用于静态SQL,在描述中会给予标注。
技巧一:尽量使用类似的SQL语句,这样Oracle本身通过SGA中的共享池来直接对该SQL语句进行缓存,那么在下一次执行类似语句时就直接调用缓存中已解析过的语句,以此来提高执行效率。
技巧二:当涉及到集合单元的时候,尽量使用批联编。比如需要对id为100和101的员工的薪水加薪10%,一般情况下应该为如下形式:

 1 declare
 2 type num_list is varray(20) of number;
 3 v_id num_list :=num_list(100,101);
 4 begin
 5 ...
 6 for i in v_id.first .. v_id.last loop
 7 ...
 8 execute immediate ‘update emp
 9 set =salary*1.2
10 where id=:1 ‘
11 using v_id(i);
12 end loop;
13 end;

对于上面的处理,当数据量大的时候就会显得比较慢,那么如果采用批联编的话,则整个集合首先一次性的传入到SQL引擎中进行处理,这样比单独处理效率要高的多,进行批联编处理的代码如下:

 1 declare
 2 type num_list is varray(20) of number;
 3 v_id num_list :=num_list(100,101);
 4 begin
 5 ...
 6 forall i in v_id.first .. v_id.last loop
 7 ...
 8 execute immediate ‘update emp
 9 set =salary*1.2
10 where id=:1 ‘
11 using v_id(i);
12 end loop;
13 end;

这里是使用forall来进行批联编,这里将批联编处理的情形作一个小结:
1) 如果一个循环内执行了insert,delete,update等语句引用了集合元素,那么可以将其移动到一个forall语句中。
2) 如果select into,fetch into 或returning into 子句引用了一个集合,应该使用bulk collect 子句进行合并。
3) 如有可能,应该使用主机数组来实现在程序和数据库服务器之间传递参数。
技巧三:使用NOCOPY编译器来提高PL/SQL性能。缺省情况下,out类型和in out类型的参数是由值传递的方式进行的。但是对于大的对象类型或者集合类型的参数传递而言,其希望损耗将是很大的,为了减少损耗,可以采用引用传递的方式,即在进行参数声明的时候引用NOCOPY关键字来说明即可到达这样的效果。比如创建一个过程:

create or replace procedure test(p_object in nocopy square)...end;

其中square为一个大的对象类型。这样只是传递一个地址,而不是传递整个对象了。显然这样的处理也是提高了效率。
4. 小结
本文对动态SQL的编译原理、开发过程以及开发技巧的讨论,通过本文的介绍后,相信读者对动态SQL程序开发有了一个总体的认识,为今后深入的工作打下一个良好的基础。

一、为什么要使用动态执行语句?

由于在PL/SQL 块或者存储过程中只支持DML语句及控制流语句,并不支持DDL语句,所以Oracle动态执行语句便应允而生了。关于DDL与DML的区别,请参见:DDL语句与DML语句及DCL和TCL

二、动态执行语句怎么用?

动态执行语句代替了Oracle 8i中的DBMS_SQL Package包。

1)在PL/SQL中运行SQL语句,例如:

示例一:

BEGIN 
              EXECUTE IMMEDIATE ‘select count(username)
from user_users‘;     --DML每条语句必须以分号结尾
       END;

示例二:

BEGIN
               EXECUTE IMMEDIATE  ‘ALTER TABLE a RENAME TO
EXAMPLE‘;    --DDL
        END;

你可能会问不是只DDL语句需要用动态语句执行吗?是的,你说的完全正确。但是DML语句用动态语句执行也可以。

即:DDL语句只能用动态执行语句来执行,DML语句亦可用动态语句来执行。

    2)使用using给动态语句传值,例如:

DECLARE
                e_name VARCHAR2(10);
--声明变量e_name
                e_age
INT;                        --声明变量e_age
         BEGIN
               
e_name :=  ‘sillylaura‘;      --给变量e_name赋值
                e_age :=
21;                     --给变量e_age 赋值
                EXECUTE IMMEDIATE
‘insert into Example values(seq_add_by_one.nextval,:2,:3)‘ using
e_name,e_age;  --DML             END;

3)使用动态语句赋值(select 列名 into 变量 from ……)

         DECLARE
                        temp INT;

BEGIN
                        EXECUTE IMMEDIATE ‘SELECT COUNT(*)
FROM dual‘  INTO temp; --DML

dbms_output.put_line(temp);
         END;

4)传递并检索值:into用在using之前。

DECLARE
                   temp INT;
                   test
VARCHAR2(10);
         BEGIN
                 test :=
‘ok‘;
                 EXECUTE immediate ‘SELECT COUNT(*) FROM dual where
dummy = :1 GROUP BY dummy‘ INTO temp USING
test;
                 dbms_output.put_line(temp ||‘  ‘|| test);
        
EXCEPTION WHEN OTHERS  THEN 
                 dbms_output.put_line(‘It has no
data!‘);
         END;

三、动态语句小结

    1. DDL语句只能用动态执行语句来执行,DML语句亦可用动态语句来执行。
    2. 在使用select……into子句为变量赋值时,into字句必须写在单引号外面。
    3. 在同时使用select……into子句和using时,注意二者的顺序:into用在using之前,且都在单引号外面。
    4. 注意写上必要的异常错误处理。
时间: 2024-08-11 07:13:04

【转】Oracle 执行动态语句的相关文章

Oracle执行SQL语句的过程

转载至:http://blog.csdn.net/aqszhuaihuai/article/details/7024551 当我们提交一条sql语句时,Oracle会做哪些操作呢? Oracle会为每个用户进程分配一个服务器进程:service process(实际情况应该区分专用服务器和共享服务器),当service process接收到用户进程提交的sql语句时,服务器进程会对sql语句进行语法和词法分析. 名词解释: 语法分析:语句本身正确性. 词法分析:对照数据字典中检查表,索引,视图和

sql 执行动态语句

没看明白,可不可以描述清楚点哦 收获园豆:5 回复 | artwl | 专家六级 |园豆:16486 | 2011-09-01 09:10 exec (select  top 2 * from pubuser.pfs_usermexcept select  top 1 * from pubuser.pfs_userm)的之為 id    name1     張三我現在取name的值 支持(0)反对(0)回复 | soarfe | 园豆:146 (初学一级) | 2011-09-01 09:45

Oracle本地动态 SQL

本地动态 SQL 首先我们应该了解什么是动态 SQL,在 Oracle数据库开发 PL/SQL块中我们使用的 SQL 分为:静态 SQL语句和动态 SQL语句.所谓静态 SQL指在 PL/SQL块中使用的 SQL语句在编 译时是明确的,执行的是确定对象.而动态 SQL是指在 PL/SQL块编译时 SQL语句是不确定 的,如根据用户输入的参数的不同而执行不同的操作.编译程序对动态语句部分不进行处理, 只是在程序运行时动态地创建语句.对语句进行语法分析并执行该语句. Oracle中动态 SQL可以通

Oracle之sql语句优化

项目中虽然使用了orm映射,但Oracle系统的优化还是很有价值的,这里从sql语句的角度对常用的语句做下总结. 1.from字段中的优化: Oracle安照从右到左的顺序加载表数据,应该把可以排除数据最多的表放到后面(基础表). 比如,在关联查询中,把课程表放到后面,成绩表放到前面,因为课程表数据一般比较少,关联的时候可以快速的过滤掉一些成绩数据. 2.where中的优化: 对可以过滤数据最多的,放到后面,原理也是Oracle执行从下到上(从右到左)的顺序. 3.使用列名替代*: 省去从字典表

使用Oracle的DBMS_SQL包执行动态SQL语句

使用Oracle的DBMS_SQL包执行动态SQL语句 引用自:http://blog.csdn.net/ggjjzhzz/archive/2005/10/17/507880.aspx 引用自:http://www.cnblogs.com/simonhaninmelbourne/archive/2013/01/23/2872438.html 在某些场合下,存储过程或触发器里的SQL语句需要动态生成.Oracle的DBMS_SQL包可以用来执行动态SQL语句.本文通过一个简单的例子来展示如何利用D

Java下拼接执行动态SQL语句(转)

在实际业务中经常需要拼接动态SQL来完成复杂数据计算,网上各类技术论坛都有讨论,比如下面这些问题: http://bbs.csdn.net/topics/390876591 http://bbs.csdn.net/topics/390981627 https://www.linkedin.com/groups/SQL-Query-Help-needed-137774.S.5948812806903119877?trk=groups_items_see_more-0-b-ttl http://bb

Java下拼接执行动态SQL语句

Java拼接动态SQL的一般做法有       1.使用动态语句 很多数据库都提供了处理动态SQL的语法,如Oracle的EXECUTE IMMEDIATE语句.MSSQL的EXEC和SP_EXECUTESQL.Mysql的预处理语句等.这些功能让我们在数据库端来处理动态查询提供了极大遍历,但这种方式只适用于相对简单地动态查询,复杂的情况经常会采用下面的方式. 2.使用存储过程 对于复杂的情况,一般会在存储过程中来拼接动态SQL.使用存储过程完成相对灵活,但编码复杂度过高,有时运行效率较低. 3

sql server、db2、oracle 存储过程动态sql语句示例

Oracle CREATE OR REPLACE PROCEDURE a_test AS t_sql VARCHAR2(2000); t_a VARCHAR2(20); t_b VARCHAR2(20); t_c VARCHAR2(20); t_d VARCHAR2(20); BEGIN t_c := 'f'; t_d := 'g'; --这里可为insert 等任何sql语句. t_sql := 'SELECT MAX(a), MAX(b) FROM t1 WHERE c = :tempC O

执行Sql语句,包括存储过程,可以动态生成返回实体

1 /// <summary> 2 /// 执行Sql语句 3 /// </summary> 4 public static class DatabaseExtend 5 { 6 /// <summary> 7 /// 执行任何SQL语句,通用所有的数据库(SQLServer,MySql,Oracle等),利用EMIT快速反射,得到动态类型实体,支持参数查询,防止sql注入. Created by ZhangQC 8 /// </summary> 9 ///