Oracle-动态sql学习笔记,由易至难讲解七个例子

本文章的内容来源于对oracle课堂上讲的内容做出的笔记

静态sql和动态sql

·静态sql:

静态 SQL 是在编译时写死的 SQL 语句,即在程序编写阶段,SQL 语句已经被固定下来。

特点:

1.预编译: SQL 语句在程序编译时就会被解析、优化,并生成执行计划,然后存储在数据库中。
2.性能: 由于编译时已经确定了执行计划,因此执行时性能相对较高,因为不需要解析和生成执行计划。
3.安全性: 相对较高,因为 SQL 语句是在编译时确定的,不容易受到 SQL 注入等攻击。

例子:

SELECT * FROM employees WHERE department_id = 10;

·动态sql:

动态 SQL 是在运行时构建和执行的 SQL 语句,允许根据程序运行时的条件来生成不同的 SQL 语句

特点:

1.灵活性: 允许在运行时动态构建 SQL 语句,根据需要进行条件判断、循环等,使得程序更加灵活。
2.执行计划: SQL 语句在运行时解析和生成执行计划,可能会导致一些性能损失,因为这个过程在运行时发生。
3.安全性: 相对较低,因为动态 SQL 可能会受到 SQL 注入攻击,必须谨慎处理输入的参数。

DECLARE
  v_department_id NUMBER := 10;
  v_sql_statement VARCHAR2(100);
BEGIN
  v_sql_statement := 'SELECT * FROM employees WHERE department_id = ' || v_department_id;
  EXECUTE IMMEDIATE v_sql_statement;
END;

什么时候使用动态sql

1.由于在PL/SQL中只能执行静态的查询和DML语句,因此要执行DDL语句或DCL语句,必须借助于动态SQL语句
2.在开发报表或一些复杂的应用程序逻辑时,如果要基于参数化的查询方式,比如动态的表字段和动态的表名称时,可以使用动态SQL语句
3.基于数据表存储业务规则和软件代码,可以将很多的业务规则的代码写在一个表的记录中,在程序需要时检索不同的业务逻辑代码动态的执行

下面用几个例子,从简单到复杂讲解动态sql的几种使用

例子一讲解(基础)

DECLARE
sql_stmt1 VARCHAR2(128);
BEGIN
sql_stmt1:='INSERT INTO rooms 
VALUES (99000, ''Building 7'', 110, 50, ''Discussion Room E'')';
EXECUTE IMMEDIATE sql_stmt1;
COMMIT;
END;

sql_stmt1 被赋予一个包含 INSERT 语句的字符串。这个 INSERT 语句的目的是向名为 rooms 的表中插入一行记录,包括房间号、建筑名称、楼层、容量和房间类型等信息。EXECUTE IMMEDIATE 语句用于在运行时执行动态生成的 SQL 语句。在这里,它执行了 sql_stmt1 中存储的 INSERT 语句,COMMIT是提交事务的命令。在数据库操作中,当你执行一些修改数据的操作时,比如 INSERT、UPDATE 或 DELETE,最后需要使用 COMMIT 语句来确保这些修改永久保存到数据库中

例子二讲解(使用绑定变量)

DECLARE
  v_department_id NUMBER;
  v_department_name VARCHAR2(100);
  v_sql_statement VARCHAR2(200);
BEGIN
  -- 使用 & 符号定义输入参数
  v_department_id := &input_department_id;
  -- 构建动态SQL语句,使用 :department_id 作为绑定变量
  v_sql_statement := 'SELECT department_name FROM departments WHERE department_id = :department_id';
  -- 执行动态SQL语句,并将输入的部门ID传递给绑定变量 :department_id
  EXECUTE IMMEDIATE v_sql_statement INTO v_department_name USING v_department_id;
  -- 输出查询结果
  DBMS_OUTPUT.put_line('部门名称为: ' || v_department_name);
END;

在这个示例中,&input_department_id 是一个替换变量,当代码运行时,系统将提示用户输入一个部门ID。这个输入的部门ID将被赋值给v_department_id,然后用作动态SQL语句中的绑定变量:department_id。这样,在执行动态SQL语句时,用户输入的值将被正确地用于查询操作,最后结果会显示查询到的部门名称。

这种方式对于需要用户交互式输入参数来动态构建SQL语句的情况非常有用,可以根据用户输入灵活地执行查询或其他数据库操作,需要注意的是:

这个地方的冒号以及后面的一堆字符串(遇见空格结束)合起来代表一个占位符,后面这个字符串是可以随意取名的,最后使用USING这个关键字放替代这个占位符的真正的变量,当然,当有多个绑定变量的时候,可以放多个占位符,然后,using后面也可以跟多个变量,用逗号分割

例子三讲解(执行动态PL/SQL块)

DECLARE
plsql_block VARCHAR2(500);
BEGIN
plsql_block := '
BEGIN 
EXECUTE IMMEDIATE ''TRUNCATE TABLE temp_table'';
FOR v_Counter IN 1..50 LOOP
INSERT INTO temp_table
VALUES (v_Counter, ''Loop Index'');
END LOOP; 
END;';
EXECUTE IMMEDIATE plsql_block;
COMMIT;
END;

这个代码执行的内容实际上是plsql_block字符串当中的语句,首先会对temp_table进行TRUNCATE(截断),然后在表中插入50行数据

例子四讲解(使用RETURNING INTO

DECLARE
sql_stmt1 VARCHAR2(500);
v_room_id NUMBER(5):=99994;
v_number_seats NUMBER(4);
BEGIN
sql_stmt1:='UPDATE rooms SET number_seats=number_seats+10'
|| ' WHERE room_id=:room_id RETURNING number_seats 
INTO :number_seats';
EXECUTE IMMEDIATE sql_stmt1 USING v_room_id 
RETURNING INTO v_number_seats;
DBMS_OUTPUT.put_line('调整后的座位数量为:'|| v_number_seats);
COMMIT;
END;

使用 EXECUTE IMMEDIATE 执行存储在 sql_stmt1 中的动态 SQL 语句。通过 USING 子句将 v_room_id 绑定到 :room_id 参数,通过 RETURNING INTO 子句将更新后的 number_seats 返回到 v_number_seats 变量中

例子五讲解(OPEN...FOR处理多行查询)

DECLARE
sql_stmt1 VARCHAR2(500);
TYPE t_RSCurType IS REF CURSOR;
v_rs_cursor t_RSCurType;
v_student_id NUMBER(5):=10000;
v_rs_record registered_students%ROWTYPE;
BEGIN
sql_stmt1 :=' SELECT student_id,department,course,grade FROM 
registered_students WHERE student_id= :student_id';
OPEN v_rs_cursor FOR sql_stmt1 USING v_student_id;
LOOP
FETCH v_rs_cursor INTO v_rs_record;
EXIT WHEN v_rs_cursor%NOTFOUND;
DBMS_OUTPUT.put_LINE('学号:' || v_rs_record.student_id || 
' ' || '系:' ||v_rs_record.department ||' 课程:' || v_rs_record.course 
||' 分数:' || v_rs_record.grade);
END LOOP;
CLOSE v_rs_cursor;
END;

t_RSCurType 是一个游标类型的声明,用于定义 v_rs_cursor 的数据类型。
v_rs_cursor 是一个 REF CURSOR 类型的游标变量。
v_student_id 是一个 NUMBER 类型的变量,赋值为 10000。
v_rs_record 是一个记录类型,用于存储 registered_students 表的一行数据。

使用 OPEN 语句打开游标,并使用 USING 子句将参数 v_student_id 绑定到 SQL 语句中的 :student_id,使用 LOOP 开始循环,通过 FETCH 语句从游标中获取数据,并将其存储到 v_rs_record 变量中。循环会在游标到达结果集的末尾时退出, 使用 CLOSE 语句关闭游标。

EXIT WHEN v_rs_cursor%NOTFOUND意思为搜到结尾就退出

总之,整个代码的作用是查询指定学生的信息并逐行输出。这里使用了动态 SQL,通过参数 v_student_id 绑定到 SQL 语句中,并且游标用于逐行处理查询结果。输出使用 DBMS_OUTPUT 函数,这通常用于在调试时输出信息

例子六讲解(批量绑定)

动态SQL批量绑定指的是在执行动态SQL语句时,一次性处理多个绑定变量值,而不是逐个处理

DECLARE
sql_stmt1 VARCHAR2(500);
TYPE t_student_id IS TABLE OF students.id%TYPE INDEX BY 
BINARY_INTEGER;
TYPE t_first_name IS TABLE OF students.first_name%TYPE INDEX 
BY BINARY_INTEGER;
TYPE t_last_name IS TABLE OF students.last_name%TYPE INDEX 
BY BINARY_INTEGER;
v_student_id_tab t_student_id;
v_first_name_tab t_first_name;
v_last_name_tab t_last_name;
v_major students.major%TYPE:=‘History‘;
BEGIN
sql_stmt1 :=' SELECT student_id,first_name,last_name FROM students 
WHERE major= :major'; 
EXECUTE IMMEDIATE sql_stmt1
BULK COLLECT INTO 
v_student_id_tab,v_first_name_tab,v_last_name_tab
USING v_major;
FOR i IN 1..v_student_id_tab.COUNT LOOP
DBMS_OUTPUT.put_line('学号:' || v_student_id_tab(i) ||' ' || '名:' 
||v_first_name_tab(i) ||' 姓:' || v_last_name_tab(i));
END LOOP;
END;

t_student_id、t_first_name、t_last_name 是三个关联数组的类型定义,索引类型为 BINARY_INTEGER。
v_student_id_tab、v_first_name_tab、v_last_name_tab 是实际的关联数组变量,所谓关联数组,以v_student_id_tab为例,简单来说就是一个数据类型和“students表当中的id”一样的元素的集合

使用 EXECUTE IMMEDIATE 执行动态 SQL 查询,并通过 BULK COLLECT INTO 子句将查询结果批量收集到关联数组中。USING 子句将 v_major 绑定到 SQL 语句中,然后使用 FOR 循环遍历关联数组,逐行输出学生的学号、名字和姓氏

整个代码的作用是查询指定专业的学生信息,并通过关联数组将学号、名字和姓氏分别存储,并通过循环逐行输出。请注意,动态 SQL 的使用使得 SQL 语句在运行时构建,而不是在编译时

例子七讲解(使用RETURNING BULK COLLECT INTO)

DECLARE
sql_stmt1 VARCHAR2(500);
TYPE t_room_id IS TABLE OF rooms.room_id%TYPE INDEX BY 
BINARY_INTEGER;
TYPE t_number_seats IS TABLE OF rooms.number_seats%TYPE 
INDEX BY BINARY_INTEGER;
v_room_id_tab t_room_id;
v_number_seats_tab t_number_seats;
v_building rooms.building%TYPE := 'Music Building';
BEGIN
sql_stmt1:='UPDATE rooms SET number_seats=number_seats+10'
|| ' WHERE building=:building RETURNING 
room_id,number_seats INTO :room_id,:number_seats';
EXECUTE IMMEDIATE sql_stmt1 USING v_building
RETURNING BULK COLLECT INTO 
v_room_id_tab,v_number_seats_tab;
FOR i IN 1..v_room_id_tab.COUNT LOOP
DBMS_OUTPUT.put_line('教室编号:'||v_room_id_tab(i) ||'调整后的
座位数量为:'|| v_number_seats_tab(i));
END LOOP;
COMMIT;
END;

整个代码块的作用是动态地更新符合条件的教室的座位数量,并通过关联数组存储并输出更新后的教室编号和座位数量。请注意,动态 SQL 的使用使得 SQL 语句在运行时构建,而不是在编译时,很多比如说关联数组的用法跟例子六相似,仅仅需要提的是这里使用动态 SQL 构建更新语句,将满足条件的教室的座位数量增加10,并通过 RETURNING INTO 子句将更新后的教室编号和座位数量返回到关联数组中

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C#中.NET 7.0 Windows窗体应用通过EF访问新建数据库

目录 一、 操作步骤 二、编写EF模型和数据库上下文 三、移植(Migrations)数据库 四、编写应用程序 五、生成效果 前文已经说过.NET Framework4.8 控制台应用通过EF访问已经建立的和新建的数据库。 前文已经说过.NET 6.0 控制台应用通过EF访问…

ajax异步传值以及后端接收参数的几种方式

异步传值 第一种呢,也是最简单的一种,通过get提交方式,将参数在链接中以问号的形式进行传递 // 前台传值方法 // 触发该方法调用ajaxfunction testAjax(yourData) {$.ajax({type: "get", // 以get方式发起请求url: "/yo…

海康设备、LiveNVR等通过GB35114国密协议对接到LiveGBS GB28181/GB35114平台的详细操作说明

一、LiveNVR通过GB35114接入LiveGBS 1.1 开启LiveGBS 35114功能 信令服务livecms.ini配置文件中[sip]增加一行gm1 启动LiveCMS 1.2 生成设备端证书 我们用LiveNVR做为设备端向LiveGBS注册,这里先生成LiveNVR的设备证书,并将LiveNVR的设备证书给LiveGB…

绩效考核管理项目|记录1

项目用C#winformSQL Server写的,现在记录一下学习到的新东西。 winform工具 splitContainer:分割出两个容器,能添加面板之类的工具 treeview:展示标签页的分层集合(用户管理、基数管理......)&#xff0…

GZ038 物联网应用开发赛题第6套

2023年全国职业院校技能大赛 高职组 物联网应用开发 任 务 书 (第6套卷) 工位号:______________ 第一部分 竞赛须知 一、竞赛要求 1、正确使用工具,操作安全规范; 2、竞赛过程中如有异议,可向现场考评…

蓝桥杯 大小写转换

islower/isupper函数 islower和issupper是C标准库中的字符分类函数&#xff0c;用于检查一个字符是否为小写字母或大写字母 需要头文件< cctype>,也可用万能头包含 函数的返回值为bool类型 char ch1A; char ch2b; //使用islower函数判断字符是否为小写字母 if(islower(…

短路语法 [SUCTF 2019]EasySQL1

打开题目 输入字符的时候啥也不回显。只有输入数字的时候页面有回显 但是当我们输入union&#xff0c;from&#xff0c;sleep&#xff0c;where&#xff0c;order等&#xff0c;页面回显nonono&#xff0c;很明显过滤了这些关键词 最开始我的思路是打算尝试双写绕过 1;ununion…

【SpringBoot】序列化和反序列化介绍

一、认识序列化和反序列化 Serialization&#xff08;序列化&#xff09;是一种将对象以一连串的字节描述的过程&#xff1b;deserialization&#xff08;反序列化&#xff09;是一种将这些字节重建成一个对象的过程。将程序中的对象&#xff0c;放入文件中保存就是序列化&…

220V交流转直流的简易电源设计

220V交流转直流的简易电源设计 设计简介设计原理电路图变压器电路交流转直流电路3.3V电源接口电路 PCB3D图 实践检验 设计简介 通过模拟电路的相关知识&#xff0c;尝试将220V的交流电转化为我们指定电压的直流电。 设计原理 将220V交流电转化为直流电的方法常用的有通过变压器…

京东数据挖掘(京东数据采集):2023年Q3电脑行业数据分析报告

近年来&#xff0c;在远程办公、远程教育等需求的刺激下&#xff0c;电脑的销售增长较为显著。不过&#xff0c;随着市场的成熟乃至饱和&#xff0c;电脑销售市场也逐渐出现增长困难、需求疲软等问题。 2023年第三季度&#xff0c;电脑市场的出货量同比下滑。根据鲸参谋电商数据…

lc121. 买卖股票的最佳时机

一次遍历&#xff0c;一边遍历一边修改买入的价格&#xff0c;一边比较取得最大利润 public class BuyAndSellStocks {public static void main(String[] args) {int[] arr {7,1,5,3,6,4};int[] arr1 {7,6,4,3,1};System.out.println(buyAndSellStocks(arr));System.out.pri…

【开发问题解决方法记录】01.dian

一些问题记录 新增角色失败&#xff1a;Error: Ajax 调用为Execute Server-Side Code返回了服务器错误ORA-01722: 无效数字。 【问题原因】&#xff1a;CREATE_BY(NUMBER类型)应该存入USER_ID(NUMBER类型)而非USER_NAME&#xff08;NVARCHAR2类型&#xff09; 【解决方法】将…

碾压Fast Request!IDEA插件推荐:Apipost-Helper

IDEA是一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它可以帮助开发人员更加高效地编写、调试和部署软件应用程序。我们在编写完接口代码后需要进行接口调试等操作&#xff0c;一般需要打开额外的调试工具&#xff0c;而今天给大家介绍一款IDEA插件&…

第十九章绘图

Java绘图类 Graphics 类 Grapics 类是所有图形上下文的抽象基类&#xff0c;它允许应用程序在组件以及闭屏图像上进行绘制。Graphics 类封装了Java 支持的基本绘图操作所需的状态信息&#xff0c;主要包括颜色、字体、画笔、文本、图像等。 Graphics 类提供了绘图常用的方法&a…

阿里云轻量级服务器搭建

购买服务器 服务器分类 轻量应用服务器 阿里云ECS 购买轻量应用服务器 实例类型 地域和可用区 *这里选择的是服务器的所在地&#xff0c;有国外和国内的 镜像 系统镜像 *系统镜像就是服务器自身的系统类型 *这里建议选择Centos7.x版本的 应用镜像 *用镜像就是在系统…

C语言——分割单向链表

本文的内容是使用C语言分割单向链表&#xff0c;给出一个链表和一个值&#xff0c;要求链表中小于给定值的节点全都位于大于或等于给定值的节点之前&#xff0c;打印原始链表的所有元素和经此操作之后链表的所有元素。 分析&#xff1a;本题只是单向链表的分割&#xff0c;不涉…

JavaScript 语句、标识符、变量

语句 JavaScript程序的单位是行(line),也就是一行一行地执行。一般情况下&#xff0c;每一行就是一个语句 var num 10; 语句以分号结尾&#xff0c;一个分号就表示一个语句结束。 标识符 标识符(identifier)指的是用来识别各种值的合法名称。最常见的标识符就是变量名标识符…

如何快速将钉钉员工信息同步到飞书

当企业内部在使用钉钉跟飞书时&#xff0c;那么当钉钉员工信息发生更改时&#xff0c;我们应该如何将信息快速同步到飞书上呢&#xff0c;接下来我们借助RestCloud AppLink平台进行演示。 第一步&#xff1a;获得钉钉以及飞书认证授权 钉钉授权 钉钉接入采用自建应用的方式&…

二维码智慧门牌管理系统升级解决方案:流量监控引领服务卓越

文章目录 前言一、流量监控功能概述二、流量监控的益处三、应用案例和成功故事四、实施和支持 前言 随着科技的不断发展&#xff0c;二维码智慧门牌管理系统在其便捷高效的管理方式下&#xff0c;深受广大用户喜爱。为了更好地满足用户需求&#xff0c;提升服务质量&#xff0…

Python OpenCV 通过trackbar调整图像亮度对比度颜色

上一篇文章通过设置固定值的方式来调整图像&#xff0c;这篇文章通过trackbar来动态调整参数&#xff0c;从而实时展现图像处理结果&#xff0c;得到想要的图像处理参数。 1. 创建trackbar import cv2 import numpy as npdef nothing(x):passcv2.namedWindow(image) # 创建5个…