首页 > 数据库 > Oracle > 动态sql和利用动态sql解决数据字典的读取
oracle中的动态sql的一些理解,动态sql通俗说也就是执行的时候才去检查的sql。
dml语句可以在pl/sql程序中加载,但是ddl语句是无法在pl/sql中执行的,这个时候就可以使用动态sql来完成ddl语句和不确定的dml语句。
首先在oracle数据库开发pl/sql程序中的sql分为:静态sql语句和动态sql语句。静态sql语句是在程序编译期间就明确的,执行的是确定的对象,而动态sql在pl/sql程序编译时sql语句是不确定的。
编译程序对动态语句部分不进行处理,只在程序运行时动态创建语句并分析语法然后执行。
procedure中包含动态sql执行ddl语句
create or replace procedure pro_test
(
table_name in varchar2,
column_1 in varchar2,
column_2 in varchar2
)
as
sql_in varchar2(50);
begin
sql_in:='create table table_name ( column_1 varchar2,column_2 varchar2)';
execute immediate sql_in;
exeception when others then
null;
end pro_test;
由于procedure是可利用pl/sql程序块,所以可以直接在pl/sql来利用动态sql执行ddl操作
declare
sql_in varchar2(100):='create table test_database as select * from v$database';
begin
execute immediate sql_in;
end;
利用动态sql执行不确定的dml操作
create or replace procedure dml_sql
(
v_ab in number,
v_ac in varchar2
)
as
sql_in varchar2(100);
begin
sql_in:='insert into dave values(:1,:2)';
execute immediate sql_in using v_ab,v_ac; --动态执行插入,上面的values的:1和:2其实相当于形式参数,而using后的id,v_ac才是实际的参数
exception when others then
null;
end dml_sql;
上面中本地动态sql执行dml语句时使用了using子句,按顺序将输入的值绑定到变量,如果要输出参数,可以执行动态sql的时候,使用returning into子句
create or replace procedure using_sql(id in number) as
p_id number;
p_name varchar2(10);
begin
execute immediate 'select id,name from dave where id=8' into p_id,p_name;
dbms_output.put_line(p_id||'的名字:'||p_name);
end;
oracle中提供了execute immediate语句来执行动态sql
execute immediate 动态sql语句 using 绑定参数列表 returing into 输出参数列表
1 动态sql是指ddl和不确定的dml
2 绑定参数列表为输入参数列表,其类型为in类型,在运行时刻和动态sql语句中的形式参数进行绑定
3 输出参数列表为动态sql语句执行后返回的参数列表
4 由于动态sql在运行时刻进行确定,相对与静态sql而言会损失一些系统性能来换取灵活性
利用动态sql在procedure中读取数据字典
在oracle中非sys用户无法在procedure读取数据字典例如
create table v_test as select * from v$logfile where 1<>1;
创建v$test表,只保留v$logfile的结构
create or replace procedure v_ab
as
begin
insert into v_test
select * from sys.v$logfile d'
commit;
end;
提示表或视图不存在,非sys用户无法读取,即使grant dba to user也一样,但是sys用户还是可以的,这应该是oracle对数据字典的一种保护吧,
此时我们利用静态sql是无法完成的,试试动态sql了
create or replace procedure v_ab
as
begin
execute immediate ('inser into v_test select * from sys.v$logfile d')
commit;
end;
下面会显示procedure已经完成。至于这里面内部的oracle对数据字典的安全机制资料中暂时找不到其中的缘由,不过对于在procedure中涉及到数据字典读取的我们确定是可以利用动态sql来处理了。
execute immediate中有个参数returning into ,刚开始我创建一个动态sql的procedure
create or replace procedure test_into_procedure
(
v_ab in varchar2,
v_ac in varchar2
)
as
v_ad varchar2(10);
v_ae varchar2(10);
sql_in varchar2(100);
begin
sql_in:='select no_stu,name_stu from student where no_stu=:1 and name_stu=:2';
execute immediate sql_in using v_ab,v_ac returning into v_ad,v_ae ;
dbms_output.put_line(v_ad||' '||v_ae);
exception when others then
null;
end;
提示创建成功,但是在
sql>execute test_into_procedure('02','Sf');
报ORA-06547: INSERT, UPDATE 或 DELETE 语句必须使用 RETURNING 子句。
后来查找资料,发现动态sql中是存在的问题的,正如oracle所说的insert update delete语句才使用returning子句,把上述的procedure中的execute immediate修改成
execute immediate sql_in into v_ad,v_ae using v_ab,v_ac ;
这样procedure也提示已经创建成功,execute时也可以达到理想的效果。oracle在编译上述中有动态sql的procedure时,个人觉得是不会理解其中的execute immediate后的内容的,因为动态sql吗,oracle只是在执行期间才去编译查看语法等,所以当存在动态sql的程序块中我们还是需要认真的去查看,本来写代码就是一个比谁细心的工作。
[@more@]来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/25362835/viewspace-1053041/ ,如需转载,请注明出处,否则将追究法律责任。