Oracle数据库中RETURNING子句

RETURNING子句允许您检索插入、删除或更新所修改的列(以及基于列的表达式)的值。如果不使用RETURNING,则必须在DML语句完成后运行SELECT语句,才能获得更改列的值。因此,RETURNING有助于避免再次往返数据库,即PL/SQL块中的另一个上下文切换。

RETURNING子句可以返回多行数据,在这种情况下,您将使用RETURNING BULK COLLECT INTO窗体。

您还可以在RETURNING子句中调用聚合函数,以获取DML语句更改的多行中的列的总和、计数等。

最后,还可以将RETURNING与EXECUTE IMMEDIATE一起使用(用于动态构建和执行的SQL语句)。

1、基本用法

1.1、单行操作:

当对单行数据进行DML操作时,可以使用RETURNING子句将受影响行的列值返回给变量。

DECLARE  v_empno employees.EMPLOYEE_ID%TYPE;  v_ename employees.FIRST_NAME%TYPE;  
BEGIN  UPDATE employees SET FIRST_NAME = 'superdb' WHERE EMPLOYEE_ID = 206 RETURNING EMPLOYEE_ID, FIRST_NAME INTO v_empno, v_ename;  DBMS_OUTPUT.PUT_LINE('Updated EMPLOYEE_ID: ' || v_empno || ', FIRST_NAME: ' || v_ename);  
END;
/Updated EMPLOYEE_ID: 206, FIRST_NAME: superdbPL/SQL procedure successfully completed.

1.2、多行操作:

当对多行数据进行DML操作时,需要使用PL/SQL的集合类型(如TABLE OF类型或嵌套表)来接收返回的多行数据。

示例(使用BULK COLLECT INTO):


HR@orcl> select EMPLOYEE_ID, FIRST_NAME,SALARY FROM employees WHERE DEPARTMENT_ID = 110 ;EMPLOYEE_ID FIRST_NAME               SALARY
----------- -------------------- ----------205 Shelley                   12008206 William                    8300DECLARE  TYPE emp_tab IS TABLE OF employees.EMPLOYEE_ID%TYPE INDEX BY PLS_INTEGER;  v_empnos emp_tab;  TYPE name_tab IS TABLE OF employees.FIRST_NAME%TYPE INDEX BY PLS_INTEGER;  v_enames name_tab;  
BEGIN  -- 正确的多列多行处理示例:  UPDATE employees SET FIRST_NAME = 'John Doe' WHERE DEPARTMENT_ID = 110   RETURNING EMPLOYEE_ID, FIRST_NAME BULK COLLECT INTO v_empnos, v_enames; -- 遍历并输出  FOR i IN 1 .. v_empnos.COUNT LOOP  DBMS_OUTPUT.PUT_LINE('Empno: ' || v_empnos(i) || ', Ename: ' || v_enames(i));  END LOOP;  
END;
/
Empno: 205, Ename: John Doe
Empno: 206, Ename: John DoePL/SQL procedure successfully completed.

2、使用RECORD类型

对于需要同时处理多列数据的情况,可以使用PL/SQL的RECORD类型来定义一个能够包含多列数据的复合类型,然后结合BULK COLLECT INTO来使用。

DECLARE  TYPE emp_rec IS RECORD (  empno employees.EMPLOYEE_ID%TYPE,  ename employees.FIRST_NAME%TYPE  );  TYPE emp_tab IS TABLE OF emp_rec INDEX BY PLS_INTEGER;  v_emps emp_tab;  
BEGIN  -- 多列多行处理示例UPDATE employees SET FIRST_NAME = 'superdb' WHERE DEPARTMENT_ID = 110  RETURNING EMPLOYEE_ID, FIRST_NAME BULK COLLECT INTO v_emps;  -- 遍历并输出    FOR i IN 1 .. v_emps.COUNT LOOP  DBMS_OUTPUT.PUT_LINE('Empno: ' || v_emps(i).empno || ', Ename: ' || v_emps(i).ename);  END LOOP;  
END;
/
Empno: 205, Ename: superdb
Empno: 206, Ename: superdbPL/SQL procedure successfully completed.

3、RETURNING子句中调用聚合函数

You can also call aggregate functions in the RETURNING clause to obtain sums, counts and so on of columns in multiple rows changed by the DML statement.
还可以在RETURNING子句中调用聚合函数,以获取DML语句更改的多行中的列的总和、计数等。


HR@orcl> select EMPLOYEE_ID, FIRST_NAME,SALARY FROM employees WHERE DEPARTMENT_ID = 110 ;EMPLOYEE_ID FIRST_NAME               SALARY
----------- -------------------- ----------205 Shelley                   12008206 William                    8300-- 您可以使用组函数执行另一个SQL语句来检索这些信息。DECLARE l_total INTEGER; 
BEGIN UPDATE employees SET salary = salary * 2 WHERE DEPARTMENT_ID = 110;-- 要做SUM运算,需要写很多代码。SELECT SUM (salary) INTO l_total FROM employees WHERE DEPARTMENT_ID = 110;DBMS_OUTPUT.put_line (l_total); 
END;-- 可以在PL/SQL中执行计算。使用RETURNING可以收回所有修改后的工资。然后对它们进行迭代,一条语句完成总和。DECLARE l_salaries   DBMS_SQL.number_table; l_total      INTEGER := 0; 
BEGIN UPDATE employees SET salary = salary * 2 WHERE DEPARTMENT_ID = 110RETURNING salary BULK COLLECT INTO l_salaries; FOR indx IN 1 .. l_salaries.COUNT LOOP l_total := l_total + l_salaries (indx); END LOOP; DBMS_OUTPUT.put_line (l_total); 
END;
/

在这里插入图片描述

您可以在RETURNING子句中直接调用SUM、COUNT等,从而在将数据返回到PL/SQL块之前执行分析。非常酷

Yes! You can call SUM, COUNT, etc. directly in the RETURNING clause and thereby perform analytics before you return the data back to your PL/SQL block. Very cool.

HR@orcl> select EMPLOYEE_ID, FIRST_NAME,SALARY FROM employees WHERE DEPARTMENT_ID = 110 ;EMPLOYEE_ID FIRST_NAME               SALARY
----------- -------------------- ----------205 Shelley                   12008206 William                    8300DECLARE l_total INTEGER; 
BEGIN UPDATE employees SET salary = salary * 2 WHERE DEPARTMENT_ID = 110RETURNING SUM (salary) INTO l_total; DBMS_OUTPUT.put_line (l_total); 
END;
/

在这里插入图片描述

4、RETURNING与EXECUTE IMMEDIATE一起使用

you can also use RETURNING with EXECUTE IMMEDIATE (for dynamically constructed and executed SQL statements).
还可以将RETURNING与EXECUTE IMMEDIATE一起使用(用于动态构建和执行的SQL语句)

4.1、在执行动态SQL语句时,利用RETURNING子句返回单行

DECLARE  l_EMPLOYEE_ID   employees.EMPLOYEE_ID%TYPE;  
BEGIN  EXECUTE IMMEDIATE q'[UPDATE employees  SET FIRST_NAME = FIRST_NAME || '-1' WHERE EMPLOYEE_ID=206RETURNING EMPLOYEE_ID INTO :one_para_id]'       RETURNING INTO l_EMPLOYEE_ID;  DBMS_OUTPUT.put_line (l_EMPLOYEE_ID);   
END;
/

在这里插入图片描述

4.2、在执行动态SQL语句时,利用RETURNING子句返回多行

DECLARE  l_EMPLOYEE_ID   DBMS_SQL.number_table;  
BEGIN  EXECUTE IMMEDIATE q'[UPDATE employees  SET FIRST_NAME = FIRST_NAME || 'list' WHERE DEPARTMENT_ID = 110RETURNING EMPLOYEE_ID INTO :para_list]'       RETURNING BULK COLLECT INTO l_EMPLOYEE_ID;  FOR indx IN 1 .. l_EMPLOYEE_ID.COUNT  LOOP  DBMS_OUTPUT.put_line (l_EMPLOYEE_ID (indx));  END LOOP;  
END;
/

在这里插入图片描述

5、限制和注意事项

  • RETURNING子句不能与并行DML操作或远程对象一起使用。

  • 在通过视图向基表中插入数据时,RETURNING子句只能与单基表视图一起使用。

  • 对于UPDATE和DELETE语句,RETURNING子句可以返回旧值(在Oracle 23ai/c及更高版本中增强)和新值,但对于INSERT语句,它只返回新值(因为插入前没有旧值)。

  • 在使用RETURNING子句时,必须确保返回的列与INTO子句中指定的变量类型兼容。

  • 在动态SQL中使用RETURNING子句时,需要注意绑定变量的使用,并且RETURNING BULK COLLECT INTO通常需要在

6、Oracle 23ai/c及更高版本中

在Oracle 23c及更高版本中,你可以使用FLASHBACK QUERY或AS OF VERSIONS BETWEEN子句(在适当的情况下)与RETURNING子句结合来访问旧值,但这通常不是直接返回旧值和新值的方式。实际上,更常见的是利用Oracle的闪回技术(如Flashback Data Archive)或触发器(Triggers)来捕获旧值。

但是,对于UPDATE和DELETE操作,如果你想要在同一个操作中同时获取旧值和新值,你可能需要采取以下策略之一:

  1. 使用触发器:在UPDATE或DELETE操作之前,使用触发器来捕获旧值,并将它们存储在另一个表或PL/SQL变量中。然后,你可以通过RETURNING子句获取新值。
  2. 使用PL/SQL变量:如果你正在执行单行操作,你可以在PL/SQL中先查询要更新的行以获取旧值,然后执行UPDATE或DELETE操作,并使用RETURNING子句获取新值。
  3. 利用Oracle的内置功能(如果可用):在某些Oracle版本中,可能有特定的内置函数或特性允许你同时访问旧值和新值,但这通常不是通过RETURNING子句直接实现的。
  4. 使用版本化表(如Oracle Total Recall或Flashback Data Archive):这些特性允许你查询表的历史版本,从而可以间接地获取旧值。
  5. 在SQL*Plus或SQLcl中使用SET SERVEROUTPUT ON和DBMS_OUTPUT.PUT_LINE:虽然这不会直接返回旧值和新值到客户端,但你可以在PL/SQL块中使用这些工具来打印出你在执行DML操作时捕获的旧值和新值。

请记住,RETURNING子句本身在Oracle 23c及更高版本中并没有直接提供返回旧值和新值的功能。相反,它主要用于在DML操作后返回新值给PL/SQL程序或触发器中的变量。如果你需要旧值,你可能需要结合使用其他Oracle特性或策略。

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

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

相关文章

Plotly:原理、使用与数据可视化的未来

文章目录 引言Plotly的原理Plotly的基本使用安装Plotly创建基本图表定制图表样式 Plotly的高级特性交互式图表图表动画图表集成 结论 引言 在当今的数据驱动世界中,数据可视化已经成为了一个至关重要的工具。它允许我们直观地理解数据,发现数据中的模式…

CXL-GPU: 全球首款实现百ns以内的低延迟CXL解决方案

数据中心在追求更高性能和更低总拥有成本(TCO)的过程中面临三大主要内存挑战。首先,当前服务器内存层次结构存在局限性。直接连接的DRAM与固态硬盘(SSD)存储之间存在三个数量级的延迟差异。当处理器直接连接的内存容量…

VideoPrism——探索视频分析领域模型的算法与应用

概述 论文地址:https://arxiv.org/pdf/2402.13217.pdf 视频是我们观察世界的生动窗口,记录了从日常瞬间到科学探索的各种体验。在这个数字时代,视频基础模型(ViFM)有可能分析如此海量的信息并提取新的见解。迄今为止,…

【vuejs】vue-router 路由跳转参数传递详解和应用场景及技巧

1. Vue2 Router 路由基础 1.1 路由定义 路由定义是Vue Router中实现页面路由跳转的基础。在Vue2中,路由的定义通常在应用的入口文件或路由配置文件中进行。路由定义涉及到路径模式(path)、视图组件(component)以及一…

【数据分析思维--史上最全最牛逼】

前言: 💞💞大家好,我是书生♡,主要和大家分享一下数据分析的思维!怎么提好我们对于业务的判断是非常重要的!!!希望对大家有所帮助。 💞💞代码是你…

采煤机作业3D虚拟仿真教学线上展示增强应急培训效果

在化工行业的生产现场,安全永远是首要之务。为了加强从业人员的应急响应能力和危机管理能力,纷纷引入化工行业工艺VR模拟培训,让应急演练更加生动、高效。 化工行业工艺VR模拟培训软件基于真实的厂区环境,精确还原了各类事件场景和…

医疗器械FDA | 医疗器械软件如何做源代码审计?

医疗器械网络安全测试https://link.zhihu.com/?targethttps%3A//www.wanyun.cn/Support%3Fshare%3D24315_ea8a0e47-b38d-4cd6-8ed1-9e7711a8ad5e 医疗器械源代码审计是一个确保医疗器械软件安全性和可靠性的重要过程。以下是医疗器械源代码审计的主要步骤和要点,以…

Vue3 sortablejs 表格拖拽后,表格无法更新的问题处理

实用sortablejs在vue项目中实现表格行拖拽排序 你可能会发现,表格排序是可以实现,但是我们基于数据驱动的vue中关联的数据并没有发生变化, 如果你的表格带有列固定(固定列实际上在dom中有两个表格,其中固定的列在一个表格中&…

【Python】优雅的快速选择 - 快速排序 - 随机快速排序

快速选择(递归实现版) 这里给出以 “leetcode215. 数组中的第K个最大元素”为例的代码。 class Solution:def findKthLargest(self, nums, k):self.nums numsn len(nums)return self.quickSelect(0,n-1,n-k)def quickSelect(self,l,r,k): # 手撸快速…

Vue3实战笔记(64)—Vue 3自定义指令的艺术:实战中的最佳实践

文章目录 前言一、一些简单的Vue3自定义指令超实用案例总结 前言 书接上文,在Vue3中,自定义指令是一种强大的工具,允许我们扩展HTML元素的功能。通过自定义指令,我们可以创建可重用的行为,并将它们绑定到任何元素上。…

订单折扣金额分摊算法|代金券分摊|收银系统|积分分摊|分摊|精度问题|按比例分配|钱分摊|钱分配

一个金额分摊的算法,将折扣分摊按比例(细单实收在总体的占比)到各个细单中。 此算法需要达到以下要求: 折扣金额接近细单总额,甚至折扣金额等于细单金额,某些时候甚至超过细单总额,要保证实收不…

游泳哪个牌子好?6大游泳耳机选购技巧总结分享

游泳耳机作为水上运动爱好者和游泳专业人士的必备装备,不仅要能够抵御水的侵入,还要提供清晰的音质和舒适的佩戴体验。在市面上,不同品牌的游泳耳机琳琅满目,选择起来可能会令人头疼。本文旨在为您提供一份详尽的游泳耳机选购指南…

每日一练 - Routing Policy节点逻辑

01 真题题目 一个 routing-policy 下可以有多个节点,不同节点号用 node 标识,每个节点下可以有多个if-match 和 apply 子句,下面哪些描述是错误的? A. 不同节点之间是“或"的关系 B. 当路由与该节点的任意一个 if-match 条件匹配失败后,系统自动转入下一节点…

Gemma轻量级开放模型在个人PC上释放强大性能,让每个桌面秒变AI工作站

Google DeepMind团队最近推出了Gemma,这是一个基于其先前Gemini模型研究和技术的开放模型家族。这些模型专为语言理解、推理和安全性而设计,具有轻量级和高性能的特点。 Gemma 7B模型在不同能力领域的语言理解和生成性能,与同样规模的开放模型…

名企专访|对抗价格内卷,格行随身WiFi如何持续三年爆火引领潮流

近期要是问网红达人最喜欢带货的单品是什么?那一定有格行随身WiFi的一席之地。能聚集了如此多的明星达人,仅仅是一句带货收益高显然无法说服大家。显然这里面还有着不为人知的秘密,先锋财经特意专访了格行随身WiFi的创始人刘永先先生&#xf…

8.x86游戏实战-OD详解

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 上一个内容:7.x86游戏实战-C实现跨进程读写-跨进程写内存 工具下载:下载 OllyI…

嵌入式Linux之Uboot简介和移植

uboot简介 uboot 的全称是 Universal Boot Loader,uboot 是一个遵循 GPL 协议的开源软件,uboot是一个裸机代码,可以看作是一个裸机综合例程。现在的 uboot 已经支持液晶屏、网络、USB 等高级功能。 也就是说,可以在没有系统的情况…

[我靠升级逆袭成为大师]韩漫日漫无删减完整版,免费在线观看漫画

[我靠升级逆袭成为大师]韩漫日漫无删减完整版,免费在线观看漫画 不能多说,怕审-核不过,自己看图吧。 目前统计【统计日期:2024-07-03】: 完结的有:420部。 连载的有:308部,持续更…

生单链路流程复杂,涉及到上下游商品、库存、营销、风控、拆单、校验、落库等等十多个节点操作,需要保证数据的完整性和正确性

处理复杂的生单链路流程,确保数据的完整性和正确性,需要一个综合的策略,包括但不限于以下几个方面: 1. **流程设计**: - 明确每个节点的职责和输入输出,确保流程的逻辑清晰。 2. **数据校验**&#xf…

python库(1):Nuitka库

1 Nuitka介绍 Nuitka是一个 Python 解释器的替代品,支持CPython提供的代码,可编译 Python 代码到 C 程序,并使用 libpython 来执行这些代码,就像 CPython 一样。 这让你可以在没有安装 Python 的环境中运行 Python 程序&#xf…