动态SQL详解

动态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;

/

原文地址:https://www.cnblogs.com/kawashibara/p/9097308.html

时间: 2024-10-09 15:32:49

动态SQL详解的相关文章

MyBatis的动态SQL详解

MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑,本文详解mybatis的动态sql,需要的朋友可以参考下 MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力.如果你有使用 JDBC 或其他 相似框架的经验,你就明白条件地串联 SQL 字符串在一起是多么的痛苦,确保不能忘了空 格或在列表的最后省略逗号.动态 SQL 可以彻底处理这种痛苦. 通常使用动态SQL不可能是独立的一部分,MyBatis当然使用一种强大的动态SQL语言来改进这种

Oracle中动态SQL详解(EXECUTE IMMEDIATE)

Oracle中动态SQL详解(EXECUTE IMMEDIATE) 2017年05月02日 18:35:48 悠悠倾我心 阅读数:744 标签: oracle动态sqloracle 更多 个人分类: 数据库 Oracle中动态SQL详解 1.静态SQLSQL与动态SQL Oracle编译PL/SQL程序块分为两个种:其一为前期联编(early binding),即SQL语句在程序编译期间就已经确定,大多数的编译情况属于这种类型:另外一种是后期联编(late binding),即SQL语句只有在运

MyBatis 动态sql详解

MyBatis的动态sql语句 1.if 条件 2.choose , when 和 otherwise条件 3.where 条件 where条件:1.自动加上where.2.如果where子句以and或者or开头,则自动删除第一个and或者or..所以我们不需要自己加where 4.trim 条件 trim条件和where条件类似但是功能更强大:不仅可以替换掉子句开头的and或者or,还提供了加前缀和后缀的功能. 5.forEach循环 6.set 条件 set条件:自动加上set,自动去除最后

Oracle中动态SQL详解

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

MyBatis动态SQL详解

MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) trim where set foreach if就是简单的条件判断,利用if语句我们可以实现某些简单的条件选择.先来看如下一个例子: <select id="dynamicIfTest" parameterType="Blog" resultType=&quo

(转)Oracle中动态SQL详解

本文转载自:http://www.cnblogs.com/gaolonglong/archive/2011/05/31/2064790.html 1.静态SQLSQL与动态SQL Oracle编译PL/SQL程序块分为两个种:其一为前期联编(early binding),即SQL语句在程序编译期间就已经确定,大多数的编译情况属于这种类型:另外一种是后期联编(late binding),即SQL语句只有在运行阶段才能建立,例如当查询条件为用户输入时,那么Oracle的SQL引擎就无法在编译期对该程

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

1.if标签 接口中方法:public List<Employee> getEmpsByEmpProperties(Employee employee); XML中:where 1=1必不可少 <select id="getEmpsByEmpProperties" resultType="com.mybatis.entity.Employee"> select * from t_employee where 1=1 <if test=&

Qt on Android: Qt Quick 组件与对象动态创建详解

在<Qt on Android: Qt Quick 事件处理之信号与槽>一文中介绍自定义信号时,举了一个简单的例子,定义了一个颜色选择组件,当用户在组建内点击鼠标时,该组件会发出一个携带颜色值的信号,当时我使用 Connections 对象连接到组件的 colorPicked 信号,改变文本的颜色. 当时用到的 Component . Loader 两个特性,一直没来得及介绍,可能很多人都还在雾里看花呢.这次呢,我们就来仔仔细细地把他们讲清楚. 请给我的参赛文章<Qt on Androi

1.7动态输入详解

1.7动态输入详解 动态输入在绘图区域中的光标附近提供命令界面就像它在命令行中所做的一样. 区别是用户的注意力可以保持在光标附近. 动态输入不会取代命令窗口. 控制动态输入设置: 动态输入有三个组件:光标(指针)输入.标注输入.动态提示 注:按下F12键可以临时关闭动态输入 原文地址:https://www.cnblogs.com/chenxi188/p/10921841.html