Oracle数据库中的动态SQL(Dynamic SQL)

Oracle数据库中的动态SQL是一种在运行时构建和执行SQL语句的技术。与传统的静态SQL(在编写程序时SQL语句就已经确定)不同,动态SQL允许开发者在程序执行过程中根据不同的条件或用户输入来构建SQL语句。这使得动态SQL在处理复杂查询、存储过程中灵活处理未知或变化的数据结构时非常有用。

1、 动态SQL的类型

Oracle中动态SQL主要有两种形式:

  1. 本地动态SQL(Native Dynamic SQL)

    • 使用EXECUTE IMMEDIATE语句来执行单个的SQL语句或PL/SQL匿名块。
    • 主要用于执行不需要返回结果的SQL语句,如INSERT、UPDATE、DELETE、DDL(数据定义语言)语句等。
    • 也可以使用INTO子句将查询结果存储在PL/SQL变量中。
  2. DBMS_SQL包

    • 提供了一套用于执行动态SQL语句的接口,允许执行更复杂的动态SQL,包括查询和DML操作。
    • 可以处理游标和绑定变量,使得处理查询结果集和参数化查询成为可能。
    • 使用步骤包括打开游标、绑定变量、执行SQL语句、处理结果集(如果有的话)、关闭游标。

2、 使用EXECUTE IMMEDIATE

EXECUTE IMMEDIATE语句非常适合执行简单的动态SQL语句,如:

2.1、从动态PL/SQL块调用子程序

Invoking Subprogram from Dynamic PL/SQL Block

In this example, the dynamic PL/SQL block is an anonymous PL/SQL block that invokes a subprogram created at schema level.

create or replace procedure sp_insert_dept
( deptid in out number,dname in varchar2,mgrid in number,locid in number
) authid definer as
begindeptid := departments_seq.nextval;insert into departments (DEPARTMENT_ID,DEPARTMENT_NAME,MANAGER_ID, LOCATION_ID) values(deptid,dname,mgrid,locid);commit;
end;
/--  定义输入参数并执行
DECLAREplsql_block VARCHAR2(500);new_deptid  NUMBER(4);new_dname   VARCHAR2(30) := 'super';new_mgrid   NUMBER(6)    := 200;new_locid   NUMBER(4)    := 1700;
BEGIN-- Dynamic PL/SQL block invokes subprogram:plsql_block := 'BEGIN sp_insert_dept(:a, :b, :c, :d); END;';/* Specify bind variables in USING clause.Specify mode for first parameter.Modes of other parameters are correct by default. */EXECUTE IMMEDIATE plsql_block USING IN OUT new_deptid, new_dname, new_mgrid, new_locid;
END;
/
-- 执行结果  
deptid = 280 new_dname= dbms_output.put_line new_mgrid= 202 new_locid= 3200PL/SQL procedure successfully completed.-- 检查表数据
HR@192.168.80.190:1521/racdb> select * from departments;DEPARTMENT_ID DEPARTMENT_NAME                MANAGER_ID LOCATION_ID
------------- ------------------------------ ---------- -----------10 Administration                        200        170020 Marketing                             201        180030 Purchasing                            114        170040 Human Resources                       203        240050 Shipping                              121        1500。。。。。。。。中间省略    。。。。。。。。。。。。。280 super                                 200        1700

2.2、用BOOLEAN形式参数动态调用子程序

Dynamically Invoking Subprogram with BOOLEAN Formal Parameter

In this example, the dynamic PL/SQL block is an anonymous PL/SQL block that invokes a subprogram that has a formal parameter of the PL/SQL data type BOOLEAN.

CREATE OR REPLACE PROCEDURE sp_test_boolean (x BOOLEAN) AUTHID DEFINER AS
BEGINIF x THENDBMS_OUTPUT.PUT_LINE('x is true');END IF;
END;
/DECLAREdyn_stmt VARCHAR2(200);b        BOOLEAN := TRUE;
BEGINdyn_stmt := 'BEGIN sp_test_boolean(:x); END;';EXECUTE IMMEDIATE dyn_stmt USING b;
END;
/
-- 执行结果
x is truePL/SQL procedure successfully completed.
-- 注意执行成功的数据库版本oracle19c
-- 测试如果是oracle11g的环境会报错
ERROR at line 6:
ORA-06550: line 6, column 36:
PLS-00457: expressions have to be of SQL types
ORA-06550: line 6, column 3:
PL/SQL: Statement ignored

2.3、用RECORD形式参数动态调用子程序

Dynamically Invoking Subprogram with RECORD Formal Parameter

In this example, the dynamic PL/SQL block is an anonymous PL/SQL block that invokes a subprogram that has a formal parameter of the PL/SQL (but not SQL) data type RECORD. The record type is declared in a package specification, and the subprogram is declared in the package specification and defined in the package body.

CREATE OR REPLACE PACKAGE pkg_record_datatype 
AUTHID DEFINER 
ASTYPE rec IS RECORD (n1 NUMBER, n2 NUMBER);PROCEDURE sp_record_datatype (x OUT rec, y NUMBER, z NUMBER);
END pkg_record_datatype ;
/CREATE OR REPLACE PACKAGE BODY pkg_record_datatype 
ASPROCEDURE sp_record_datatype (x OUT rec, y NUMBER, z NUMBER) ASBEGINx.n1 := y;x.n2 := z;END sp_record_datatype ;
END pkg_record_datatype ;
/DECLAREr       pkg_record_datatype.rec;dyn_str VARCHAR2(3000);
BEGINdyn_str := 'BEGIN pkg_record_datatype.sp_record_datatype(:x, 100, 1008); END;';EXECUTE IMMEDIATE dyn_str USING OUT r;DBMS_OUTPUT.PUT_LINE('r.n1 = ' || r.n1);DBMS_OUTPUT.PUT_LINE('r.n2 = ' || r.n2);
END;
/

执行结果 – 注意(oracle19c版本),oracle11g依旧报错

r.n1 = 100
r.n2 = 1008

3、 使用DBMS_SQL包

DBMS_SQL包用于执行更复杂的动态SQL,包括查询和需要处理结果集的DML操作。以下是使用DBMS_SQL包的基本步骤:

3.1、DBMS_SQL.RETURN_RESULT Procedure

In this example, the procedure p invokes DBMS_SQL.RETURN_RESULT without the optional to_client parameter (which is TRUE by default). Therefore, DBMS_SQL.RETURN_RESULT returns the query result to the subprogram client (the anonymous block that invokes p). After p returns a result to the anonymous block, only the anonymous block can access that result.

CREATE OR REPLACE PROCEDURE sp_dbms_sql_test AUTHID DEFINER ASc1 SYS_REFCURSOR;c2 SYS_REFCURSOR;
BEGINOPEN c1 FORSELECT first_name, last_nameFROM employeesWHERE employee_id = 176;DBMS_SQL.RETURN_RESULT (c1);-- Now p cannot access the result.OPEN c2 FORSELECT city, state_provinceFROM locationsWHERE country_id = 'AU';DBMS_SQL.RETURN_RESULT (c2);-- Now p cannot access the result.
END;
/BEGINsp_dbms_sql_test ;
END;
/

执行结果

ResultSet #1FIRST_NAME           LAST_NAME
-------------------- -------------------------
Jonathon             TaylorResultSet #2CITY                           STATE_PROVINCE
------------------------------ -------------------------
Sydney                         New South Wales

注意:Oracle12c中PL/SQL(DBMS_SQL)新特性之隐式语句结果,DBMS_SQL.RETURN_RESULT隐式返回查询结果,Oracle11g执行上面的示例会报错,不支持RETURN_RESULT。

动态SQL为Oracle数据库应用提供了极大的灵活性和功能,但使用时也需要注意SQL注入等安全问题。因此,在处理用户输入时,应该使用参数化查询或适当的输入验证来防止潜在的安全风险。

3.2、DBMS_SQL.GET_NEXT_RESULT

希望通过客户端应用来处理这些结果集,这可以通过DBMS_SQL包的 GET_NEXT_RESULT过程来解决

DECLAREl_sql_cursor    PLS_INTEGER;l_ref_cursor    SYS_REFCURSOR;l_return        PLS_INTEGER;l_col_cnt       PLS_INTEGER;l_desc_tab      DBMS_SQL.desc_tab;l_count         NUMBER;l_EMPLOYEE_ID   EMPLOYEES.EMPLOYEE_ID%TYPE;l_FIRST_NAME    EMPLOYEES.FIRST_NAME%TYPE;l_LAST_NAME    EMPLOYEES.LAST_NAME%TYPE;
BEGIN-- 执行过程l_sql_cursor := DBMS_SQL.open_cursor(treat_as_client_for_results => TRUE);DBMS_SQL.parse(c             => l_sql_cursor,statement     => 'BEGIN get_result_emp(30); END;',language_flag => DBMS_SQL.native);l_return := DBMS_SQL.execute(l_sql_cursor);-- 循环遍历每个结果集LOOP-- 获取下个结果集BEGINDBMS_SQL.get_next_result(l_sql_cursor, l_ref_cursor);EXCEPTIONWHEN NO_DATA_FOUND THENEXIT;END;-- 检查结果集列数l_return := DBMS_SQL.to_cursor_number(l_ref_cursor);DBMS_SQL.describe_columns (l_return, l_col_cnt, l_desc_tab);l_ref_cursor := DBMS_SQL.to_refcursor(l_return);-- 根据列数处理结果集CASE l_col_cntWHEN 1 THENDBMS_OUTPUT.put_line('The column is COUNT:');FETCH l_ref_cursorINTO  l_count;DBMS_OUTPUT.put_line('l_count=' || l_count);CLOSE l_ref_cursor;WHEN 3 THENDBMS_OUTPUT.put_line('The columns are EMPLOYEE_ID and FIRST_NAME and l_LAST_NAME:');LOOPFETCH l_ref_cursorINTO  l_EMPLOYEE_ID, l_FIRST_NAME,l_LAST_NAME;EXIT WHEN l_ref_cursor%NOTFOUND;DBMS_OUTPUT.put_line('l_EMPLOYEE_ID=' || to_char(l_EMPLOYEE_ID) || CHR(9) || 'l_FIRST_NAME=' || l_FIRST_NAME || CHR(9)|| 'l_LAST_NAME=' || l_LAST_NAME);END LOOP;CLOSE l_ref_cursor;ELSEDBMS_OUTPUT.put_Line('I wasn''t expecting that!');END CASE;END LOOP;
END;
/

执行结果

The columns are EMPLOYEE_ID and FIRST_NAME and l_LAST_NAME:
l_EMPLOYEE_ID=114       l_FIRST_NAME=Den        l_LAST_NAME=Raphaely
l_EMPLOYEE_ID=115       l_FIRST_NAME=Alexander  l_LAST_NAME=Khoo
l_EMPLOYEE_ID=116       l_FIRST_NAME=Shelli     l_LAST_NAME=Baida
l_EMPLOYEE_ID=117       l_FIRST_NAME=Sigal      l_LAST_NAME=Tobias
l_EMPLOYEE_ID=118       l_FIRST_NAME=Guy        l_LAST_NAME=Himuro
l_EMPLOYEE_ID=119       l_FIRST_NAME=Karen      l_LAST_NAME=Colmenares
The column is COUNT:
l_count=107PL/SQL procedure successfully completed.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/879596.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【计算机网络】UDP 协议详解及其网络编程应用

文章目录 一、引言二、UDP1、UDP的协议格式2、UDP 报文的解包和分用3、UDP面向数据报的特点 三、UDP输入输出四、UDP网络编程 一、引言 UDP(User Datagram Protocol,用户数据报协议)是一种网络通信协议,它属于传输层的协议。是一…

PostgreSQL - tutorial

本文翻译整理自:官方文档 Preface 和 第一部分(I. Tutorial) 有需要的可以前往官方文档查看:https://www.postgresql.org/docs/15/index.html 文章目录 序言1.什么是PostgreSQL?2. PostgreSQL简史2.1 伯克利POSTGRES项…

【linux】ln 命令

ln 命令在 Linux 系统中用于创建链接(links),它允许你创建一个文件的引用,指向该文件系统中的另一个位置。这种链接可以是硬链接(hard link)或软链接(软连接,也称为符号链接&#xf…

HTTP中的Cookie与Session

一、背景 HTTP协议是无状态无连接的。 无状态:服务器不会保存客户端历史请求记录,每一次请求都是全新的。 无连接:服务器应答后关闭连接,每次请求都是独立的。 无状态就导致服务器不认识每一个请求的客户端是否登陆过。 这时…

【贪心算法】贪心算法

贪心算法简介 1.什么是贪心算法2.贪心算法的特点3.学习贪心的方向 点赞👍👍收藏🌟🌟关注💖💖 你的支持是对我最大的鼓励,我们一起努力吧!😃😃 1.什么是贪心算法 与其说是…

Spring为什么要用三级缓存解决循环依赖?

Spring为什么要用三级缓存解决循环依赖? 1. Spring是如何创建一个bean对象2. Spring三级缓存2.1 一级缓存:单例池,经历过完整bean生命,单例Bean对象2.2 二级缓存:提前暴露的Bean2.3 三级缓存:打破循环 3. S…

计算机网络通关学习(一)

简介 之前我通过王道的考研课进行了计算机网络的学习,但是在秋招准备过程中发现之前的笔记很多不足,学习的知识不够深入和巩固,所以再重新对《图解HTTP》&《图解TCP/IP》进行深度学习后,总结出了此篇博客,由于内容…

【C#】添加临时环境变量

在C#中,可以通过System.Environment类来添加临时环境变量。临时环境变量只在当前进程中有效,进程结束后变量即失效,不会写入系统的Path中。 using System;class Program {static void Main(){// 设置临时环境变量Environment.SetEnvironment…

08_Python数据类型_字典

Python的基础数据类型 数值类型:整数、浮点数、复数、布尔字符串容器类型:列表、元祖、字典、集合 字典 字典(Dictionary)是一种可变容器模型,它可以存储任意类型对象,其中每个对象都存储为一个键值对。…

openmv与stm32通信

OpenMV与STM32之间的通信是嵌入式系统中常见且重要的一环,尤其在机器视觉和自动控制领域。两者结合可以实现图像识别、数据处理以及基于识别结果的硬件控制,从而广泛应用于智能小车、机器人、无人机等领域。以下将详细阐述OpenMV与STM32之间的通信过程&a…

存储数据的树形结构

目录 1、二叉查找树 2、平衡二叉树AVL Tree 3 、平衡多叉树B-Tree 4、BTree树 5 、红黑树 红黑树的应用 6.平衡树的旋转 mysql 索引数据结构: Btree 索引是B树在数据库中的一种实现,最为常见的。B树 中的B代表平衡,而不是二叉 1、二…

带你如何使用CICD持续集成与持续交付

目录 一、CICD是什么 1.1 持续集成(Continuous Integration) 1.2 持续部署(Continuous Deployment) 1.3 持续交付(Continuous Delivery) 二、git工具使用 2.1 git简介 2.2 git的工作流程 2.3 部署g…

如何用 Scrapy 爬取网站数据并在 Easysearch 中进行存储检索分析

做过数据分析和爬虫程序的小伙伴想必对 Scrapy 这个爬虫框架已经很熟悉了。今天给大家介绍下,如何基于 Scrapy 快速编写一个爬虫程序并利用 Easysearch 储存、检索、分析爬取的数据。我们以极限科技的官网 Blog 为数据源,做下实操演示。 安装 scrapy 使…

3. Python计算水仙花数

Python计算水仙花数 一、什么是水仙花数? 百度答案 二、怎样使用Python计算水仙花数? 这里需要for循环,if判断,需要range()函数,需要知道怎么求个位数,十位数,百位数… 1. For循环 语句结…

CTFHub技能树-SQL注入-整数型注入

一、手动注入 思路:注入点->库->表->列->数据 首先使用order by探测有几列 http://challenge-215beae2f0b99b12.sandbox.ctfhub.com:10800/?id1 order by 2 我们发现order by 2 的时候有回显,到了order by 3 的时候就没有回显了&#xf…

k8s的环境配置

一、前期系统环境准备 准备3台主机:硬盘50G cpu2个 内存2G 1、3台主机同时配置 1)关闭防火墙与selinux、NetworkManager [rootk8s-master ~]# systemctl stop firewalld[rootk8s-master ~]# systemctl disable firewalldRemoved symlink /etc/systemd/…

CSS---序号使用css设置,counter-reset、counter-increment、content配合实现备注文案的序号展示

直接上代码&#xff0c;全代码copy即可使用! <template><div class"reminder"><span class"Bold_12_body" style"line-height: 8vw">温馨提示&#xff1a;</span><br /><div class"rule-container"…

共享内存C(Linux)

在学习的时候遇到问题&#xff0c;就是将结构体作为共享内存时将string类型置入结构体内&#xff0c;导致程序出现段错误&#xff0c;后来经过排查发现共享内存是c语言的库不支持string类型&#xff0c;需要用char name[20]代替。 1.在Linux中如何查看共享内存 &#xff08;1&…

【Hot100】LeetCode—84. 柱状图中最大的矩形

目录 1- 思路题目识别单调栈 2- 实现⭐84. 柱状图中最大的矩形——题解思路 3- ACM 实现 原题链接&#xff1a;84. 柱状图中最大的矩形 1- 思路 题目识别 识别1 &#xff1a;给定一个数组 heights &#xff0c;求解柱状图的最大面积 单调栈 使用 Stack 来实现&#xff0c;遍…

go语言中的数组指针和指针数组的区别详解

1.介绍 大家知道C语言之所以强大&#xff0c;就是因为c语言支持指针&#xff0c;而且权限特别大&#xff0c;c语言可以对计算机中任何内存的指针进行操作&#xff0c;这样自然而然也会带来一些不安全的因素&#xff0c;所以在golang中&#xff0c;「取消了对指针的一些偏移&…