动态SQL

在之前用户所编写的PL/SQL程序时有一个最大的特点:就是所操作的数据库对象(例如:表)必须存在,否则创建的子程序就会出问题,而这样的操作在开发之中被称为静态SQL操作,而动态SQL操作可以让用户在定义程序时不指定具体的操作对象,而在执行时动态的传入所需要的数据库对象,从而使程序变得更加的灵活。

创建一个功能,输入表名,输出表中有多少行,若没有这个表,则创建这个表。

首先禁用所有触发器

GRANT CREATE ANY TABLE TO SCOTT

create or replace function get_table_count_fun(p_table_name varchar2) return number as

v_sql_statement varchar2(200);--定义操作的SQL语句

v_count number;--保存表中记录

begin

select count(*) into v_count from user_tables where table_name=UPPER(p_table_name);

if v_count=0 then--数据表不存在

v_sql_statement:='CREATE TABLE '|| p_table_name ||'(id number ,name varchar2(30) not null)';--创建数据表,注意此处不要忽略空格,按照正常写create table语句的格式加空格,否则无法识别

execute immediate v_sql_statement;--执行动态SQL

end if;

v_sql_statement:=' select count(*) from '|| p_table_name;--查询数据表记录,注意加空格

execute immediate v_sql_statement into v_count;--执行动态SQL并保存数据记录

return v_count;

end;

/

declare

v1 varchar2(100);

begin

v1:=get_table_count_fun('t100');--查看t100表

dbms_output.put_line(v1);

end;

/

EXECUTE IMMEDIATE语句

在动态SQL之中EXECUTE IMMEDIATE是最为重要的执行命令,使用此语句可以方便的在PL/SQL程序之中执行DML(INSERT/UPDATE/DELETE/单列SELECT)、DDL(CREATE/ALTER/DROP)、DCL(GRANT/REVOKE)语句,EXECUTE IMMEDIATE语法定义如下:

EXECUTE IMMEDIATE 动态SQL字符串 [[BULK COLLECT]] INTO 自定义变量,...|记录类型|

[USING [IN | OUT |IN OUT|绑定参数,...]

[[RETURNING | RETURN][BULK COLLECT] INTO 绑定参数,...];

EXECUTE IMMEDIATE由以下三个主要字句组成:

INTO:保存动态SQL执行结果,如果返回多行记录可以通过BULK COLLECT设置批量保存;

USING:用来为动态SQL设置占位符设置内容;

RETURNING | RETURN:两者使用效果一样,是取得更新表记录被影响的数据,通过BULK COLLECT来设置批量绑定。

使用动态SQL创建表和PLSQL块

declare

v_sql_statement varchar2(200);

v_count number;--保存查找结果

begin

select count(*) into v_count from user_tables where table_name='VDATA_TAB';

if v_count=0 then--数据表不存在

v_sql_statement:='CREATE TABLE vdata_tab(

id number primary key,

url varchar2(50) not null)';--定义动态SQL

execute immediate v_sql_statement;

Else--数据表存在

v_sql_statement:='TRUNCATE TABLE vdata_tab';

execute immediate v_sql_statement;

end if;

v_sql_statement:='begin

for x in 1 .. 10 loop

insert into vdata_tab(id,url) values(x,''www.vdata.com.cn''||x);

end loop;

end;';

execute immediate v_sql_statement;

commit;--提交事物

end;

/

使用绑定变量

Declare

V_sql_statement varchar2(200);

V_deptno dept.deptno%type:=60;

V_dname dept.dname%type:=’VDATA’;

V_loc dept.loc%type:=’beijing’;

Begin

V_sql_statement:=’insert into dept(deptno,dname,loc) values(:dno,:dna,:dl)’;

Execute immediate v_sql_statement using v_deptno,v_dname,v_loc;

Commit;

End;

/

如果有字段为NULL,则不能直接绑定NULL,需要通过变量设置

如果在本程序中索要增加的部门位置为NULL,则以下的设置方式是错误的:EXECUTE IMMEDIATE v_sql_statement using v_deptno,v_dname,NULL;如果现在希望LOC的内容为NULL,可以将v_loc变量设置为NULL,其他执行部分不做改变。

查询数据

declare

v_sql_statement1 varchar2(2000);

v_empno emp.empno%type:=7369;

v_emprow emp%rowtype;

begin

v_sql_statement1:='select * from emp where empno=:eno';

execute immediate v_sql_statement1 into v_emprow using v_empno;

dbms_output.put_line('ename: '||v_emprow.empno||', ename: '||v_emprow.ename||', position: '||v_emprow.job);

end;

/

通过以上的操作可以发现,所有使用绑定变量的代码都只是针对基本的数据类型,例如字符串、数字等,但是这种方式不可能针对DDL操作,例如,将要创建或阶段的表名称使用绑定变量的话就是出现错误。

创建表时使用绑定变量

DECLARE

v_sql_statement VARCHAR2(200) ;

v_table_name VARCHAR2(200) := 'mldn' ;

v_id_column VARCHAR2(200) := 'id' ;

BEGIN

v_sql_statement := 'CREATE TABLE ' || v_table_name ||' (' || v_id_column ||' NUMBER PRIMARY KEY)' ;

EXECUTE IMMEDIATE v_sql_statement ;

END  ;

更新数据,取得更新后的结果

Declare

V_sql_statement varchar2(200);--定义SQL操作语句

V_empno emp.empno%type:=7369;--要更新的雇员编号

V_salary emp.sal%type;--保存更新后的sal内容

V_job emp.job%type;--保存更新后的Job内容

Begin

V_sql_statement:=’update emp set sal=sal*1.2,job=”developer”’||’where empno=:eno returning sal.job into :salary,:job’;

Execute immediate v_sql_statement using v_empno returning into v_salary,v_job;

Dbms_output.put_line(‘salary: ‘||v_salary||’, new position: ‘||v_job);

End;

/

也可以使用RETURN接收影响数据行的数据。

在接收影响数据行数据时,也可以利用return进行操作,如下所示:

v_sql_statement:=’update emp set sal=sal*12,job=”developer” ’||’ where empno=:eno return sal,job into :salary,:job’;

Execute immediate v_sql_statement using v_empno return into v_salary,v_job;

使用return与returning相比没有任何区别

删除数据,取得删除前的结果

Declare

V_sql_statement varchar2(200);--定义SQL操作语句

V_emprow emp%rowtype;--保存emp类型

V_empno emp.empno%type:=7369;--删除的雇员编号

V_ename emp.ename%type;--删除的雇员姓名

V_sal emp.sal%type;--删除的雇员工资

Begin

V_sql_statement:=’delete from emp where empno=:eno returning ename,sal into :name,:sal;

Execute immediate v_sql_statement using v_empno returning into v_ename,v_sal;

Dbms_output.put_line(‘empno: ‘||v_empno||’, ename: ‘||v_ename||’, salary: ‘||v_sal);

End;

/

在使用USING或RETURNING语句时都可以设置参数模式(IN/OUT/IN OUT),其中对USING子句主要是使用变量定义的内容,所以默认的模式是IN模式。使用RETURNING子句时不需要设置内容,只需接收返回内容,所以其模式为OUT。

编写部门增加过程

Create or replace procedure dept_insert_proc(

P_deptno in out dept.deptno%type,--此处可以将p_deptno的内容回传

P_dname dept.dname%type,--默认为in模式

P_loc dept.loc%type) as --默认为in模式

Begin

Select max(deptno) into p_deptno from dept;--取得最大的deptno内容

P_deptno:=p_deptno+1;--让最大值部门编号+1,此处不考虑超过两位数字情况

Insert into dept(deptno,dname,loc) values (p_deptno,p_dname,p_loc);

End;

/

批量绑定

通过动态SQL进行查询或更新操作时,每次都是向数据库提交了一条操作语句,如果现在希望数据库可以一次性接收多条SQL,以及数据库可以一次性将操作结果返回到某一个集合中时,就可以采用批量处理操作完成,在进行批量处理操作中,注意依靠BULK COLLECT进行操作。

使用BULK COLLECT更新

DECLARE

TYPE ename_index IS TABLE OF emp.ename%TYPE INDEX BY PLS_INTEGER ;

TYPE job_index IS TABLE OF emp.job%TYPE INDEX BY PLS_INTEGER ;

TYPE sal_index IS TABLE OF emp.sal%TYPE INDEX BY PLS_INTEGER ;

v_ename ename_index ;

v_job job_index ;

v_sal sal_index ;

v_sql_statement VARCHAR2(200) ;         --定义动态SQL

v_deptno emp.deptno%TYPE := 10 ;        --查询10部门

BEGIN

v_sql_statement := 'UPDATE emp SET sal=sal*1.2 WHERE deptno=:dno ' ||

' RETURNING ename,job,sal INTO :ena, :ej, :es' ;-- 此时返回多行更新结果(注意空格,否则无法识别语句)

EXECUTE IMMEDIATE v_sql_statement USING v_deptno

RETURNING BULK COLLECT INTO v_ename,v_job,v_sal ;

FOR x IN 1 .. v_ename.COUNT LOOP

DBMS_OUTPUT.put_line('雇员姓名' || v_ename(x) || ',职位:' || v_job(x) || ',工资:' || v_sal(x)) ;

END LOOP ;

END ;

雇员姓名:CLARK,职位:MANAGER,工资:3528

雇员姓名:KING,职位:PRESIDENT,工资:7200

雇员姓名:MILLER,职位:CLERK,工资:1872

查询时使用BULK COLLECT

Declare

type ename_index is table of emp.ename%type index by pls_integer;

Type job_index is table of emp.job%type index by pls_integer;

Type sal_index is table of emp.sal%type index by pls_integer;

V_ename ename_index;

V_job job_index;

V_sal sal_index;

V_sql_statement varchar2(200);--定义动态SQL

V_deptno emp.deptno%type:=10;--查询10部门

Begin

V_sql_statement:=’select ename,job,sal from emp where deptno=:dno’;--此时返回多行更新结果

Execute immediate v_sql_statement

Bulk collect into v_ename,v_job,v_sal

Using v_deptno;

For x in 1..v_ename.count loop

Dbms_output.put_line(‘ename: ’||v_ename(x)||’ , position: ‘||v_job(x)||’, salary: ‘||v_sal(x));

End loop;

End;

/

FORALL

如果要向动态SQL之中设置多个绑定参数,则就必须利用FORALL语句完成,此语句的语法如下所示。

FORALL索引变量IN参数集合最小值..参数集合最大值

EXECUTE IMMEDIATE 动态SQL字符串

[USING 绑定参数|绑定参数(索引), ...]

[[RETURNING | RETURN] BULK COLLECT INTO 绑定参数集合 , ...];

通过FORALL设置多个参数

Declare

Type empno_nested is table of emp.empno%type;--定义嵌套表

Type ename_index is table of emp.ename%type index by pls_integer;--定义索引表

Type job_index is table of emp.job%type index by pls_integer;--定义索引表

Type sal_index is table of emp.sal%type index by pls_integer;--定义索引表

V_ename ename_index;--保存删除后的姓名

V_job job_index;--保存删除后的职位

V_sal sal_index;--保存删除后的工资

V_empno empno_nested:=empno_nested(7369,7566,7788);--定义要删除雇员编号

V_sql_statement varchar2(200);--动态SQL

Begin

V_sql_statement:=’delete from emp where empno=:eno’||’

Returning ename,job,sal into :ena, :ej, :es’;--删除数据SQL

FORALL x in 1 .. v_empno.count --FORALL绑定多个变量

EXECUTE IMMEDIATE v_sql_statement using v_empno(x)

Returning bulk collect into v_ename,v_job,v_sal;

For x in 1 .. v_ename.count loop

Dbms_output.put_line(‘ename: ‘||v_ename(x)||’, position: ‘||’, salary: ‘||v_sal(x));

End loop;

End;

/

处理游标操作

动态SQL操作之中,除了可以处理单行查询操作之外,也可以利用游标完成多行数据的操作,而在游标定义时也同样可以使用动态绑定变量的方式,此时就需要在打开游标变量时增加USING子句操作。

在游标中使用动态SQL

DECLARE
emp_cur SYS_REFCURSOR ; -- 定义游标变量
v_emprow emp%ROWTYPE ; -- 定义emp行类型
v_deptno emp.deptno%TYPE := 10 ; -- 定义要查询雇员的部门编号
BEGIN
OPEN emp_cur FOR 'SELECT * FROM emp WHERE deptno=:dno '
USING v_deptno ;
LOOP
FETCH emp_cur INTO v_emprow ; -- 取得游标数据
EXIT WHEN emp_cur%NOTFOUND ; -- 如果没有数据则退出
DBMS_OUTPUT.put_line('雇员姓名:' || v_emprow.ename || ',雇员职位:' || v_emprow.job) ;
END LOOP ;
CLOSE emp_cur ;
END ;

FETCH

在FETCH语句之中利用BULK COLLECT一次性将多个数据保存到集合类型之中,语法如下所示。

FETCH 动态游标 BULK COLLECT INTO 集合变量 ...;

利用FETCH保存查询结果

Declare

Emp_cur sys_refcursor;--定义游标变量

Type emp_index is table of emp%rowtype index by pls_integer;--定义索引表

V_emprow emp_index;--定义emp行类型

V_deptno emp.deptno%type:=10;--定义要查询雇员的部门编号

Begin

Open emp_cur for ‘select * from emp where deptno=:dno’

Using v_deptno;

Fetch emp_cur bulk collect into v_emprow;

Close emp_cur

For x in 1 .. v_emprow.count loop

Dbms_output.put_line(‘empno: ‘||v_emprow(x).empno||’, ename: ‘||v_emprow(x).ename||’, position: ‘||v_emprow(x).job);

End loop;

End;

/

使用动态SQL可以在依赖对象不存在时创建子程序;

动态SQL主要利用EXECUTE IMMEDIATE语句执行DML/DDL/DCL等语句操作;

如果使用了绑定变量,则必须在EXECUTE IMMEDIATE中使用USING子句设置所需要的绑定变量;

使用RETURNING或RETURN语句可以接收查询或更新后的返回结果;

使用批处理可以一次性将数据库之中取回的多个数据保存在集合里,或者使用FORALL将多个绑定参数设置到动态SQL之中。

动态显示游标

输出HR或SCOTT下每张表对应的所有记录数

declare

emp_cur sys_refcursor;

v_emprow emp%rowtype;

v_deptno emp.deptno%type:=10;

begin

open emp_cur for 'select * from emp where deptno=:dno'

using v_deptno;

loop

fetch emp_cur into v_emprow;

exit when emp_cur%notfound;

dbms_output.put_line('ename: '||v_emprow.ename||' position: '||v_emprow.job);

end loop;

close emp_cur;

end;

/

动态SQL详解的更多相关文章

  1. MyBatis的动态SQL详解

    MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑,本文详解mybatis的动态sql,需要的朋友可以参考下 MyBatis 的一个强大的特性之一通常是它 ...

  2. Oracle中动态SQL详解(EXECUTE IMMEDIATE)

    Oracle中动态SQL详解(EXECUTE IMMEDIATE) 2017年05月02日 18:35:48 悠悠倾我心 阅读数:744 标签: oracle动态sqloracle 更多 个人分类:  ...

  3. MyBatis动态SQL详解

    MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) ...

  4. Java数据持久层框架 MyBatis之API学习七(动态 SQL详解)

    对于MyBatis的学习而言,最好去MyBatis的官方文档:http://www.mybatis.org/mybatis-3/zh/index.html 对于语言的学习而言,马上上手去编程,多多练习 ...

  5. oracle中动态SQL详解

    部分内容参考网上资料 1.静态SQLSQL与动态SQL Oracle编译PL/SQL程序块分为两个种:其一为前期联编(early binding),即SQL语句在程序编译期间就已经确定,大多数的编译情 ...

  6. 超全MyBatis动态SQL详解!( 看完SQL爽多了)

    MyBatis 令人喜欢的一大特性就是动态 SQL. 在使用 JDBC 的过程中, 根据条件进行 SQL 的拼接是很麻烦且很容易出错的. MyBatis 动态 SQL 的出现, 解决了这个麻烦. My ...

  7. MyBatis探究-----动态SQL详解

    1.if标签 接口中方法:public List<Employee> getEmpsByEmpProperties(Employee employee); XML中:where 1=1必不 ...

  8. MyBatis的动态SQL详解-各种标签使用

    MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) ...

  9. (转)Oracle中动态SQL详解

    本文转载自:http://www.cnblogs.com/gaolonglong/archive/2011/05/31/2064790.html 1.静态SQLSQL与动态SQL Oracle编译PL ...

随机推荐

  1. linux每日命令(37):top命令

    top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器.下面详细介绍它的使用方法.top是一个动态显示过程,即可以通过用户按键来不断刷新 ...

  2. Android开发(十四)——SimpleAdapter与自定义控件

    ListView中可以使用SimpleAdapter进行数据与视图的绑定,但都是对已有的系统控件的绑定,如果自定义空间直接使用SimpleAdapter绑定,则会报错. 如,使用CircleImage ...

  3. cvCreateImage

    CvCreateImage函数说明 cvCreateImage是openCV中的一个函数.OpenCV是Intel公司支持的开源计算机视觉库.   cvCreateImage:   创建头并分配数据 ...

  4. vue返回上一页面如果没有上一页面返回首页

    methods: { back(){ if (window.history.length <= 1) { this.$router.push({path:'/'}) return false } ...

  5. [Object Tracking] Overview of algorithms for Object Tracking

    From: https://www.zhihu.com/question/26493945 可以载入史册的知乎贴 目标跟踪之NIUBILITY的相关滤波 - 专注于分享目标跟踪中非常高效快速的相关滤波 ...

  6. Ajax简单整理-思维导图

    图片和mmap下载地址:http://pan.baidu.com/s/1jGqUpxk

  7. ImageMagick、imagick和ghostscript三者的关联

    http://467754239.blog.51cto.com/4878013/1602518/ 一.功能概述 ImageMagick是第三方的图片处理软件,功能要比GD强大.建议两者都安装,并不冲突 ...

  8. 深入理解 Java 虚拟机之学习笔记(1)

    本书结构: 从宏观的角度介绍了整个Java技术体系.Java和JVM的发展历程.模块化,以及JDK的编译 讲解了JVM的自动内存管理,包括虚拟机内存区域的划分原理以及各种内存溢出异常产生的原因 分析了 ...

  9. mui---获取入口文件对象

    在做APP的时候,发现在Hbuilder里面,如果是已经加载过的页面,可以通过 plus.webview.getWebviewById(id),拿到加载的页面对象,这里的id默认是url,但是入口文件 ...

  10. 学习vue 2.x源码笔记

    1.响应式原理: 核心:Object.defineProperty,用法如下: var obj1 = {}; var initValue = 'hello'; Object.definePropert ...