Oracle入门(十四.18)之使用动态SQL
发布日期:2021-07-01 01:36:57 浏览次数:2 分类:技术文章

本文共 3840 字,大约阅读时间需要 12 分钟。

一、SQL的执行流程

数据库中的所有SQL语句都经历了不同的阶段:
•解析:预执行“这可能吗?”检查包括语法,对象存在,权限等
•绑定:获取语句中引用的任何变量的实际值
•执行:语句被执行。

•提取:结果返回给用户。

某些阶段可能与所有语句无关;例如,提取阶段适用于查询,但不适用于DML。

二、PL / SQL子程序中SQL的执行流程

当PL / SQL子程序中包含SQL语句时,解析和绑定阶段通常是在编译时完成的,也就是说,当过程,函数或包体是CREATEd时。

如果在创建过程时SQL语句的文本未知,该怎么办? Oracle服务器如何解析它? 它不能。 例如,假设您想要删除一个表,但用户在执行时输入表名:

CREATE PROCEDURE drop_any_table(p_table_name VARCHAR2)IS BEGIN DROP TABLE p_table_name; -- cannot be parsedEND;

三、动态SQL

您使用动态SQL来创建一个SQL语句,其中的文本事先不完全知道。
动态SQL:
•构造并存储为子程序内的字符串。
•是否包含具有不同列数据的SQL语句,或带有或不带有占位符(绑定变量)的不同条件。

•使数据定义,数据控制或会话控制语句能够从PL / SQL写入和执行。

(1)本地动态SQL

PL / SQL不支持直接写在procedure中的DDL语句。 本地动态SQL允许您通过在子程序中构建SQL并将其存储为字符串来解决此问题。 本地动态SQL:
•以PL / SQL语言直接为动态SQL提供本机支持。

•使数据定义,数据控制或会话控制语句能够从PL / SQL写入和执行。

•使用本机动态SQL语句(EXECUTE IMMEDIATE)或DBMS_SQL包执行。

•提供执行直到执行时间结构未知的SQL语句的能力。

•也可以使用OPEN-FOR,FETCH和CLOSE PL / SQL语句。

(2)使用EXECUTE IMMEDIATE语句

在PL / SQL匿名块或子程序中为原生动态SQL使用EXECUTE IMMEDIATE语句:

EXECUTE IMMEDIATE dynamic_string[INTO {define_variable [, define_variable] ... | record}][USING [IN|OUT|IN OUT] bind_argument [, [IN|OUT|IN OUT] bind_argument] ... ];
•INTO用于单行查询,并指定检索列值的变量或记录。

•USING保存所有绑定参数。 如果未指定,则默认参数模式为IN。

•dynamic_string是包含SQL语句文本的字符变量或文字。

•define_variable是一个PL / SQL变量,用于存储选定的列值。
•record是存储选定行的用户定义或%ROWTYPE记录。

•bind_argument是一个表达式,其值在执行时传递给动态SQL语句。

•USING子句保存所有绑定参数。 默认参数模式是IN。

示例1:使用DDL语句的动态SQL

在线构建动态声明:

CREATE PROCEDURE drop_any_table(p_table_name VARCHAR2) ISBEGIN EXECUTE IMMEDIATE 'DROP TABLE '||p_table_name;END;

在一个变量中构造动态语句:

CREATE PROCEDURE drop_any_table(p_table_name VARCHAR2) IS v_dynamic_stmt VARCHAR2(50);BEGIN v_dynamic_stmt := 'DROP TABLE '||p_table_name; EXECUTE IMMEDIATE v_dynamic_stmt;END;
BEGIN drop_any_table('EMPLOYEE_NAMES'); END;
示例2:使用DML语句的动态SQL

删除任何表中的所有行并返回计数:

CREATE FUNCTION del_rows(p_table_name VARCHAR2)RETURN NUMBER ISBEGIN EXECUTE IMMEDIATE 'DELETE FROM '||p_table_name; RETURN SQL%ROWCOUNT;END;

调用该函数:

DECLARE v_count NUMBER;BEGIN v_count := del_rows('EMPLOYEE_NAMES'); DBMS_OUTPUT.PUT_LINE(v_count|| ' rows deleted.');END;
示例3:使用DML语句的动态SQL

这是一个将行插入两列并调用过程的示例。

CREATE PROCEDURE add_row(p_table_name VARCHAR2, p_id NUMBER, p_name VARCHAR2) ISBEGIN EXECUTE IMMEDIATE 'INSERT INTO '||p_table_name|| ' VALUES (p_id, p_name)';END;
BEGINadd_row('EMPLOYEE_NAMES', 250, 'Chang');END;
示例4:使用本机动态SQL重新编译PL / SQL代码

您可以使用下列ALTER语句重新编译PL / SQL对象而不重新创建它们:

ALTER PROCEDURE procedure-name COMPILE;ALTER FUNCTION function-name COMPILE;ALTER PACKAGE package_name COMPILE SPECIFICATION;ALTER PACKAGE package-name COMPILE BODY;

本示例创建一个过程,用于重新编译在运行时输入其名称和类型的PL / SQL对象。

CREATE PROCEDURE compile_plsql(p_name VARCHAR2,p_type VARCHAR2,p_options VARCHAR2 := NULL) IS v_stmt VARCHAR2(200);BEGIN v_stmt := 'ALTER '||p_type||' '||p_name||' COMPILE' ||' '||p_options; EXECUTE IMMEDIATE v_stmt;END;
BEGIN compile_plsql('MYPACK','PACKAGE','BODY'); END;

四、使用DBMS_SQL包

(1)DBMS_SQL包的一些过程和功能是:

• OPEN_CURSOR

• PARSE

• BIND_VARIABLE

• EXECUTE

• FETCH_ROWS

• CLOSE_CURSOR

(2)使用带有DML语句的DBMS_SQL

删除行的示例:

CREATE OR REPLACE FUNCTION del_rows(p_table_name VARCHAR2) RETURN NUMBER IS v_csr_id INTEGER; v_rows_del NUMBER;BEGIN v_csr_id := DBMS_SQL.OPEN_CURSOR; DBMS_SQL.PARSE(v_csr_id, 'DELETE FROM '||p_table_name, DBMS_SQL.NATIVE); v_rows_del := DBMS_SQL.EXECUTE (v_csr_id); DBMS_SQL.CLOSE_CURSOR(v_csr_id); RETURN v_rows_del;END;

请将本文前面的内容与del_rows函数进行比较。 它们功能相同,但更简单?

(3)使用带有参数化DML语句的DBMS_SQL

再次,将其与本课前面的add_row过程进行比较。 你宁愿写什么?
CREATE PROCEDURE add_row (p_table_name VARCHAR2,p_id NUMBER, p_name VARCHAR2) IS v_csr_id INTEGER; v_stmt VARCHAR2(200); v_rows_added NUMBER;BEGIN v_stmt := 'INSERT INTO '||p_table_name|| ' VALUES ('||p_id||','''||p_name||''')'; v_csr_id := DBMS_SQL.OPEN_CURSOR; DBMS_SQL.PARSE(v_csr_id,v_stmt, DBMS_SQL.NATIVE); v_rows_added := DBMS_SQL.EXECUTE(v_csr_id); DBMS_SQL.CLOSE_CURSOR(v_csr_id);END;

五、本地动态SQL与DBMS_SQL包的比较

原生动态SQL

•比DBMS_SQL更易于使用

•比DBMS_SQL需要更少的代码

•通常执行速度比DBMS_SQL快,因为执行的语句较少。

转载地址:https://maokun.blog.csdn.net/article/details/80534524 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Oracle入门(十四.19)之触发器简介
下一篇:Oracle入门(十四.17)之procedure传递参数

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2024年04月14日 03时05分18秒