Oracle数据库数据编程SQL<递归函数详解>
递归函数是一种在函数体内直接或间接调用自身的函数。这种函数通过将复杂问题分解为更小的相同问题来解决特定类型的编程任务。
目录
一、递归函数基本概念
1. 递归定义
2. 递归工作原理
二、递归函数示例
1. 经典阶乘函数
2. 斐波那契数列
3. 计算数字位数
三、递归查询应用
1. 递归WITH子句(公用表表达式)
2. 层次结构查询(员工-经理关系)
四、递归函数设计要点
五、递归与迭代对比
1. 递归与迭代对比
2. 迭代实现阶乘(对比)
六、递归函数的高级应用
1. 遍历树形结构
2. 解决汉诺塔问题
七、递归的局限性及优化
1. Oracle递归深度限制
2. 尾递归优化
3. 记忆化(Memoization)优化
一、递归函数基本概念
1. 递归定义
递归函数包含两个关键部分:
-
基准条件(Base Case):确定递归何时结束,避免无限循环
-
递归条件(Recursive Case):将问题分解为更小的子问题并调用自身
2. 递归工作原理
- (1)函数检查是否满足基准条件
- (2)如果满足,返回基准值
- (3)如果不满足,将问题分解并调用自身处理更小的子问题
- (4)最终将所有子问题的结果组合成最终解
二、递归函数示例
1. 经典阶乘函数
CREATE OR REPLACE FUNCTION factorial(p_num IN NUMBER
) RETURN NUMBER
IS
BEGIN-- 基准条件:0!和1!都等于1IF p_num <= 1 THENRETURN 1;ELSE-- 递归条件:n! = n * (n-1)!RETURN p_num * factorial(p_num - 1);END IF;
END factorial;
/-- 调用示例
SELECT factorial(5) FROM dual; -- 返回120 (5! = 5×4×3×2×1 = 120)
2. 斐波那契数列
CREATE OR REPLACE FUNCTION fibonacci(p_num IN NUMBER
) RETURN NUMBER
IS
BEGIN-- 基准条件IF p_num = 0 THENRETURN 0;ELSIF p_num = 1 THENRETURN 1;ELSE-- 递归条件:F(n) = F(n-1) + F(n-2)RETURN fibonacci(p_num - 1) + fibonacci(p_num - 2);END IF;
END fibonacci;
/-- 调用示例
SELECT fibonacci(10) FROM dual; -- 返回55 (斐波那契数列第10项)
3. 计算数字位数
CREATE OR REPLACE FUNCTION count_digits(p_num IN NUMBER
) RETURN NUMBER
IS
BEGIN-- 基准条件:单个数字IF p_num BETWEEN -9 AND 9 THENRETURN 1;ELSE-- 递归条件:去掉最后一位后计数+1RETURN 1 + count_digits(TRUNC(p_num/10));END IF;
END count_digits;
/-- 调用示例
SELECT count_digits(12345) FROM dual; -- 返回5
三、递归查询应用
Oracle中的递归不仅限于PL/SQL函数,还可以用于SQL递归查询:
1. 递归WITH子句(公用表表达式)
-- 计算1到10的和
WITH recursive_sum(n, total) AS (-- 基准查询SELECT 1, 1 FROM dualUNION ALL-- 递归查询SELECT n+1, total+(n+1)FROM recursive_sumWHERE n < 10
)
SELECT * FROM recursive_sum;/*
结果:
N TOTAL
1 1
2 3
3 6
4 10
5 15
6 21
7 28
8 36
9 45
10 55
*/
2. 层次结构查询(员工-经理关系)
-- 查找员工的管理链
WITH emp_hierarchy AS (-- 基准查询:从指定员工开始SELECT employee_id, last_name, manager_id, 1 AS levelFROM employeesWHERE employee_id = 110UNION ALL-- 递归查询:向上查找经理SELECT e.employee_id, e.last_name, e.manager_id, h.level + 1FROM employees eJOIN emp_hierarchy h ON e.employee_id = h.manager_id
)
SELECT LPAD(' ', 2*(level-1)) || last_name AS management_chain
FROM emp_hierarchy
ORDER BY level DESC;/*
结果:
MANAGEMENT_CHAINKingHigginsGietz
*/
四、递归函数设计要点
-
必须存在基准条件:确保递归能够终止
-
每次递归应使问题更接近基准条件:避免无限递归
-
注意递归深度:Oracle有递归深度限制(默认约1000层)
-
性能考虑:递归可能比迭代解决方案效率低
-
内存使用:深层递归会消耗大量栈空间
五、递归与迭代对比
1. 递归与迭代对比
| 特性 | 递归 | 迭代 |
| 代码简洁性 | 更简洁 | 通常更冗长 |
| 内存使用 | 使用调用栈,可能栈溢出 | 通常更高效 |
| 性能 | 函数调用开销大 | 通常更快 |
| 适用场景 | 问题自然递归时 | 大多数情况 |
| 可读性 | 数学定义清晰时更易读 | 流程更直观 |
2. 迭代实现阶乘(对比)
CREATE OR REPLACE FUNCTION factorial_iter(p_num IN NUMBER
) RETURN NUMBER
ISv_result NUMBER := 1;
BEGINFOR i IN 1..p_num LOOPv_result := v_result * i;END LOOP;RETURN v_result;
END factorial_iter;
/
六、递归函数的高级应用
1. 遍历树形结构
CREATE OR REPLACE PROCEDURE print_folder_tree(p_folder_id IN NUMBER,p_level IN NUMBER DEFAULT 0
) ISCURSOR folder_cur ISSELECT folder_id, folder_nameFROM foldersWHERE parent_id = p_folder_id;
BEGIN-- 打印当前文件夹(带缩进)DBMS_OUTPUT.PUT_LINE(LPAD(' ', p_level*2) || 'Folder: ' || p_folder_id);-- 递归处理子文件夹FOR f_rec IN folder_cur LOOPprint_folder_tree(f_rec.folder_id, p_level + 1);END LOOP;
END print_folder_tree;
/
2. 解决汉诺塔问题
CREATE OR REPLACE PROCEDURE hanoi(p_disks IN NUMBER,p_from IN VARCHAR2,p_to IN VARCHAR2,p_aux IN VARCHAR2
) IS
BEGINIF p_disks = 1 THENDBMS_OUTPUT.PUT_LINE('移动盘子 1 从 ' || p_from || ' 到 ' || p_to);ELSE-- 将n-1个盘子从起始柱移动到辅助柱hanoi(p_disks - 1, p_from, p_aux, p_to);-- 移动第n个盘子到目标柱DBMS_OUTPUT.PUT_LINE('移动盘子 ' || p_disks || ' 从 ' || p_from || ' 到 ' || p_to);-- 将n-1个盘子从辅助柱移动到目标柱hanoi(p_disks - 1, p_aux, p_to, p_from);END IF;
END hanoi;
/-- 调用示例
EXEC hanoi(3, 'A', 'C', 'B');
七、递归的局限性及优化
1. Oracle递归深度限制
Oracle默认递归深度限制约为1000层,可通过以下方式调整:
ALTER SESSION SET recursive_with_clause = 10000; -- 增加递归WITH限制
对于PL/SQL递归函数,
可通过修改_recursive_with_balancing等隐藏参数调整限制(需DBA权限)
2. 尾递归优化
Oracle PL/SQL不自动执行尾递归优化,但可手动重构:
-- 普通递归
CREATE OR REPLACE FUNCTION sum_to_n(p_n IN NUMBER
) RETURN NUMBER
IS
BEGINIF p_n <= 1 THENRETURN 1;ELSERETURN p_n + sum_to_n(p_n - 1);END IF;
END;
/-- 尾递归形式(Oracle不会优化,但其他语言可能优化)
CREATE OR REPLACE FUNCTION sum_to_n_tail(p_n IN NUMBER,p_acc IN NUMBER DEFAULT 0
) RETURN NUMBER
IS
BEGINIF p_n <= 0 THENRETURN p_acc;ELSERETURN sum_to_n_tail(p_n - 1, p_acc + p_n);END IF;
END;
/
3. 记忆化(Memoization)优化
缓存已计算结果,避免重复计算:
CREATE OR REPLACE PACKAGE fib_pkg ASTYPE num_array IS TABLE OF NUMBER INDEX BY PLS_INTEGER;g_fib_cache num_array;FUNCTION fibonacci(p_n NUMBER) RETURN NUMBER;
END fib_pkg;
/CREATE OR REPLACE PACKAGE BODY fib_pkg ASFUNCTION fibonacci(p_n NUMBER) RETURN NUMBERISBEGIN-- 基准条件IF p_n = 0 THENRETURN 0;ELSIF p_n = 1 THENRETURN 1;END IF;-- 检查缓存IF g_fib_cache.EXISTS(p_n) THENRETURN g_fib_cache(p_n);END IF;-- 计算并缓存结果g_fib_cache(p_n) := fibonacci(p_n - 1) + fibonacci(p_n - 2);RETURN g_fib_cache(p_n);END;
END fib_pkg;
/
递归函数是解决分治问题和层次结构处理的强大工具,但需要谨慎设计以避免性能问题和栈溢出错误。在Oracle环境中,对于深度递归问题,有时使用迭代方法或递归WITH子句可能是更好的选择。
相关文章:
Oracle数据库数据编程SQL<递归函数详解>
递归函数是一种在函数体内直接或间接调用自身的函数。这种函数通过将复杂问题分解为更小的相同问题来解决特定类型的编程任务。 目录 一、递归函数基本概念 1. 递归定义 2. 递归工作原理 二、递归函数示例 1. 经典阶乘函数 2. 斐波那契数列 3. 计算数字位数 三、递归查…...
Redis-08.Redis常用命令-有序集合操作命令
一.有序集合操作命令 ZADD key score 1 member1 [score2 member2]: zadd zset 10.0 a 10.5 b ZRANGE key start stop [WITHSCORES]: zrange zset 0 -1 为何顺序为a,c,b? 因为 zrange zset 0 -1 withscores zrange key start …...
LLaMA-Factory使用实战
LLaMA-Factory使用实战 项目介绍 项目地址:https://github.com/hiyouga/LLaMA-Factory 中文文档:安装 - LLaMA Factory 快速开始文档:https://zhuanlan.zhihu.com/p/695287607(推荐参考) 远程服务器通过本地代理加…...
读一本书,骑行万里路:与维乐 Angel Rise+骑行看世界
最近读到了一本名为《自行车改变的世界:女性骑行的历史》的书,才发现原来女性的骑行自由来得并不轻易,激励着每一位女性勇敢地踏上骑行之路。而我一直在使用的维乐坐垫品牌,除了产品专业之外,也一直都非常关注女性骑行…...
【大模型】SpringBoot整合LangChain4j实现RAG检索实战详解
目录 一、前言 二、LangChain4j 介绍 2.1 什么是LangChain4j 2.2 LangChain4j 主要特点 2.3 Langchain4j 核心组件 三、RAG介绍 3.1 什么是RAG 3.2 RAG工作流程 3.2.1 补充说明 3.3 Embedding模型 3.3.1 RAG实际使用步骤 3.3.2 什么是Embedding 3.3.3 Embedding 技…...
流动的梦境:GPT-4o 的自回归图像生成深度解析
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
北大人工智能研究院朱松纯:“中国的AI叙事” 存在认知偏差
3月29日,在2025中关村论坛通用人工智能论坛上,北京通用人工智能学院院长,北京大学人工智能研究院、智能学院院长朱松纯表示,目前,行业对AI的讨论几乎被大模型能力所占据,而基础学科、原始创新与智能本质的研…...
习题1.26
解释题,说简单也简单,难在如何表达清楚。 首先解释下代码的变化 (defn expmod[base exp m](cond ( exp 0) 1(even? exp) (mod (square (expmod base (/ exp 2) m)) m):else (mod (* base (expmod base (- exp 1) m)) m)))(defn expmod[base exp m](co…...
FPGA调试笔记
XILINX SSTL属性电平报错 错误如下: [DRC BIVRU-1] Bank IO standard Vref utilization: Bank 33 contains ports that use a reference voltage. In order to use such standards in a bank that is not configured to use INTERNAL_VREF, the banks VREF pin mu…...
基于Java(SSM)+Mysql实现移动大厅业务办理(增删改查)
基于 SSM 框架的移动业务大厅 数据库需要自行创建! 一、 整体基本实现情况 对本学期的 Java 作业 1 的 SOSO 移动大厅进行改进, 基于 SSM、JSP、Maven、Tomcat、MySQL 等实现。 二、 实现详情 1、 工程结构图 2、 工程结构各部分实现 (…...
音视频 ColorSpace色彩空间详解
前言 基于前篇介绍YUV格式,本文继续介绍另一个重要概念颜色空间,又叫色彩空间;主要用于在音视频开发中的色彩空间转换。 色彩空间Color Space 色彩空间由色彩模型和色域共同定义。当色彩模型与特定的描述相关联以后,就称为色彩空间。 色彩模型Color Model 色彩模型Col…...
【字符设备驱动开发–IMX6ULL】(一)简介
【字符设备驱动开发–IMX6ULL】(一)简介 一、Linux驱动与裸机开发区别 1.裸机驱动开发回顾 1、底层,跟寄存器打交道,有些MCU提供了库。 spi.c:主机驱动(换成任何一个设备之后只需要调用此文件里面的…...
45 55跳跃游戏解题记录
先是55跳跃游戏,暴力解法会怎样?会超出时间限制,而且有很多细节要注意: func canJump(nums []int) bool {// 处理空数组情况,当nums只剩一个元素时,nums[i:]导致越界。if len(nums) 0 {return false}// 如…...
C++_STL之list篇
一、list的介绍 std::list是C标准模板库(STL)中的一个双向链表容器。与vector和deque不同,list不支持随机访问,但它在任何位置插入和删除元素都非常高效。 1.基本特性 (1)双向链表结构:每个元素都包含指向前驱和后继的指针 (2)非连续存储&…...
Go中的逃逸分析
什么是逃逸? 逃逸是指一个变量本来应该分配在栈(stack)上,但由于某些原因,最终被分配到了堆(heap)上。 类比: 栈就像一个临时的快餐盒,用来存放短期使用的数据。堆就像…...
Spring 声明式事务 万字详解(通俗易懂)
目录 Δ前言 一、声明式事务快速入门 1.为什么需要声明式事务? 2.定义: 3.应用实例: 二、声明式事务的传播机制 1.引出问题: 2.传播机制分类: 3.应用实例: 三、声明式事务的隔离机制 1.四种隔离级别&…...
MySQL 当中的锁
MySQL 当中的锁 文章目录 MySQL 当中的锁MySQL 中有哪些主要类型的锁?请简要说明MySQL 的全局锁有什么用?MySQL 的表级锁有哪些?作用是什么?元数据锁(MetaData Lock,MDL)意向锁(Inte…...
fyrox 2D和3D游戏的制作
目录 fyrox介绍 1. 核心特性 1.1 高性能渲染 1.2 跨平台支持 1.3 物理引擎集成 1.4 脚本系统 1.5 场景管理 2. 架构设计 2.1 渲染器 2.2 资源管理器 2.3 输入系统 2.4 音频引擎 2.5 网络模块 3. 使用场景 3.1 2D游戏 3.2 3D游戏 3.3 模拟与教育应用 4. 在游戏…...
[Linux]基础IO
基础IO C文件IO相关操作磁盘文件与内存文件inode(index node)硬链接与软连接硬链接软连接总结 动静态库静态库动态库总结 C文件IO相关操作 当前路径:进程运行的时候,所处的路径叫做当前路径 打开文件的时候,一定是进…...
力扣刷题-热题100题-第27题(c++、python)
21. 合并两个有序链表 - 力扣(LeetCode)https://leetcode.cn/problems/merge-two-sorted-lists/description/?envTypestudy-plan-v2&envIdtop-100-liked 常规法 创建一个新链表,遍历list1与list2,将新链表指向list1与list2…...
Vue3 其它API Teleport 传送门
Vue3 其它API Teleport 传送门 在定义一个模态框时,父组件的filter属性会影响子组件的position属性,导致模态框定位错误使用Teleport解决这个问题把模态框代码传送到body标签下...
windows下安装sublime
sublime4 alpha 4098 版本 下载 可以根据待破解的版本选择下载 https://www.sublimetext.com/dev crack alpha4098 的licence 在----- BEGIN LICENSE ----- TwitterInc 200 User License EA7E-890007 1D77F72E 390CDD93 4DCBA022 FAF60790 61AA12C0 A37081C5 D0316412 4584D…...
golang 的strconv包常用方法
目录 1. 字符串与整数的转换 2. 字符串与浮点数的转换 3. 布尔值的转换 4. 字符串的转义 5. 补充:rune 类型的使用 方法功能详解 代码示例: 1. 字符串与整数的转换 方法名称功能描述示例Atoi将字符串转换为十进制整数。strconv.Atoi("123&q…...
ComplexE的代码注释
目录 dataloader.pymodel.pyrun.py 先安装软件,配置环境,搞了一周。再看代码写注释搞了一周。中间隔了一周。再安装环境跑代码又一周。最后结果是没结果。自己电脑内存带不动。还不想配电脑,又不会用GPU服务器。哭死哭死。心态崩了。直接发吧…...
vector<int> 的用法
vector<int> 是 C 标准模板库(STL)中的一个容器,用于存储动态大小的整数序列。以下是它的主要用法: 基本操作 1. 创建和初始化 #include <vector> using namespace std;vector<int> v1; // 空vector vector<int>…...
Java高级JVM知识点记录,内存结构,垃圾回收,类文件结构,类加载器
JVM是Java高级部分,深入理解程序的运行及原理,面试中也问的比较多。 JVM是Java程序运行的虚拟机环境,实现了“一次编写,到处运行”。它负责将字节码解释或编译为机器码,管理内存和资源,并提供运行时环境&a…...
名言警句1
1、嫉妒是欲望的衍生,而欲望则是成长的驱动,说到底每个人都是为了成长,为了不居人后,在成长的过程中,我们可以让欲望枝繁叶茂,但不能让嫉妒开花结果 2、人生无法奢求更多,我们有健康的身体&…...
【STL】queue
q u e u e queue queue 是一种容器适配器,设计为先进先出( F i r s t I n F i r s t O u t , F I F O First\ In\ First\ Out,\ FIFO First In First Out, FIFO)的数据结构,有两个出口,将元素推入队列的操作称为 p u …...
QXmpp入门
QXmpp 是一个基于 Qt 的 XMPP (Jabber) 协议实现库,用于开发即时通讯(IM)、聊天应用和实时协作系统。它支持客户端和服务端开发,提供完整的 XMPP 核心功能扩展。 1. 核心功能 XMPP 核心协议支持 支持 RFC 6120 (XMPP Core) 和 RFC 6121 (XMPP IM) 基础功能:认证、在线状态…...
使用cursor为代码添加注释
1. add-comments.md英文 You are tasked with adding comments to a piece of code to make it more understandable for AI systems or human developers. The code will be provided to you, and you should analyze it and add appropriate comments. To add comments to …...
