sql-递归查询
有的情况下,我们需要用递归的方法整理数据,这才程序中很容易做到,但是在数据库中,用SQL语句怎么实现?下面我以最典型的树形结构来说明下如何在Oracle使用递归查询。
为了说明方便,创建一张数据库表,用于存储一个简单的树形结构
Sql代码
1.create table TEST_TREE
2.(
3. ID NUMBER,
4. PID NUMBER,
5. IND NUMBER,
6. NAME VARCHAR2(32)
7.)
ID是主键,PID是父节点ID,IND是排序字段,NAME是节点名称。
初始化几条
测试数据。
引用
ID PID IND NAME
1 0 1 根节点
2 1 1 一级菜单1
3 1 2 一级菜单2
4 1 2 一级菜单3
5 2 1 一级1子1
6 2 2 一级1子2
7 4 1 一级3子1
8 4 2 一级3子2
9 4 3 一级3子3
10 4 0 一级3子0
一、基本使用:
在Oracle中,递归查询要用到start with 。
connect by prior。
具体格式是:
Sql代码
1.SELECT column
2.FROM table_name
3.START WITH column=value
4.CONNECT BY PRIOR 父主键=子外键
对于本例来说,就是:
Sql代码
1.select d.* from test_tree d
2. start with d.pid=0
3. connect by prior d.id=d.pid
引用
ID PID IND NAME
1 0 1 根节点
2 1 1 一级菜单1
5 2 1 一级1子1
6 2 2 一级1子2
3 1 2 一级菜单2
4 1 2 一级菜单3
7 4 1 一级3子1
8 4 2 一级3子2
9 4 3 一级3子3
10 4 0 一级3子0
我们从结果中可以看到,记录已经是按照树形结构进行排列了,但是现在有个新问题,如果我们有这样的需求,就是不但要求结果按照树形结构显示,还要根据ind字段在每一个分支内进行排序,这个问题怎么处理呢?我们可能很自然的想到如下语句:
Sql代码
1.select d.* from test_tree d
2. start with d.pid=0
3. connect by prior d.id=d.pid
4. order by d.ind
ID PID IND NAME
引用
1 0 1 根节点
2 1 1 一级菜单1
5 2 1 一级1子1
6 2 2 一级1子2
4 1 2 一级菜单3
10 4 0 一级3子0
8 4 2 一级3子2
9 4 3 一级3子3
7 4 1 一级3子1
3 1 2 一级菜单2
这显然不是我们想要的结果,那下面的这个语句呢?
Sql代码
1.select d.* from (select dd.* from test_tree dd order by dd
.ind) d
2. start with d.pid=0
3. connect by prior d.id=d.pid
引用
ID PID IND NAME
1 0 1 根节点
2 1 1 一级菜单1
5 2 1 一级1子1
6 2 2 一级1子2
4 1 2 一级菜单3
10 4 0 一级3子0
8 4 2 一级3子2
9 4 3 一级3子3
7 4 1 一级3子1
3 1 2 一级菜单2
这个结果看似对了,但由于一级菜单3节点下有一个节点的ind=0,导致一级菜单2被拍到了3下面。
如果想使用类似这样的语句做到各分支内排序,则需要找到一个能够准确描述菜单级别的字段,但是对于示例表来说,不存在这么一个字段。
那我们如何实现需求呢?其实Oracle9以后,提供了一种排序“order siblings by”就可以实现我们的需求,用法如下:
Sql代码
1.select d.* from test_tree d
2. start with d.pid=0
3. connect by prior d.id=d.pid
4. order siblings by d.ind asc
结果如下:
引用
ID PID IND NAME
1 0 1 根节点
2 1 1 一级菜单1
5 2 1 一级1子1
6 2 2 一级1子2
3 1 2 一级菜单2
4 1 2 一级菜单3
10 4 0 一级3子0
7 4 1 一级3子1
8 4 2 一级3子2
9 4 3 一级3子3
这样一来,查询结果就完全符合我们的要求了。
递归查询sql语句
递归查询sql语句嘿,你要是搞数据库这一块的,那递归查询SQL语句可就像一把超级钥匙啊。
比如说,咱们公司有个部门组织架构的数据库,每个部门下面可能还有子部门,一层套一层的,就像俄罗斯套娃似的。
要是想把这整个组织架构的信息一股脑儿全找出来,普通查询就像拿个小勺子在大海里舀水,不得劲儿。
可递归查询SQL语句呢,那就像一艘超级大船,直接开进去把所有数据都给你捞出来。
我有个朋友小李,他刚开始接触数据库的时候,一看到这种层层嵌套的数据就头疼。
他就跟我说:“这可咋整啊,我感觉我在这数据迷宫里打转,出都出不来。
”我就跟他说:“你得用递归查询SQL语句啊。
”他一脸懵:“啥是递归查询SQL语句啊?”我就给他打个比方,这就好比你在一个大树林里找宝藏,宝藏可能在树根下面,也可能在树枝上面的小盒子里,你要是一个个地方慢慢找,那得找到猴年马月。
递归查询SQL 语句就像是你有个魔法地图,它能顺着树的脉络,不管是树干还是树枝,一直找下去,直到把宝藏都找出来。
递归查询SQL语句的原理有点像我们小时候玩的传话游戏。
第一个人说一句话,传给第二个人,第二个人再传给第三个人,这样一直传下去。
在SQL里,就是一个查询结果作为下一个查询的输入,就这么一环扣一环。
比如说,我们有个家族关系的数据库,里面有爷爷、爸爸、儿子这样的关系。
要想找出一个家族所有后代的信息,递归查询SQL语句就开始工作啦。
它就像一个聪明的小侦探,从爷爷那一代开始,顺着关系链一个个找下去,就像沿着家族的血脉在探索。
再说说实际的代码吧。
你看啊,在SQL里,像在Oracle数据库中,递归查询可以用CONNECT BY语句来实现。
就好像给数据搭建了一个特殊的楼梯,它能顺着这个楼梯一级一级地往上或者往下找数据。
比如说我们有个商品分类的数据库,大分类下面有小分类,小分类下面还有子分类。
我们想知道某个大分类下面所有的子分类信息,用递归查询SQL语句,就像沿着这个商品分类的“族谱”去探寻每一个成员。
sql递归 +level 查询语法
sql递归+level 查询语法在SQL中,递归查询通常涉及使用WITH RECURSIVE语句来创建递归公共表表达式(CTE)。
这允许你在查询中定义递归结构,并使用LEVEL或其他标识符来表示递归的深度。
下面是一个基本的递归查询语法示例:WITH RECURSIVE RecursiveCTE (column1, column2, ..., level) AS ( -- Anchor memberSELECT column1, column2, ..., 1 as levelFROM your_tableWHERE <your_condition>UNION ALL-- Recursive memberSELECT t.column1, t.column2, ..., r.level + 1FROM your_table tJOIN RecursiveCTE r ON <join_condition>WHERE <additional_conditions>)SELECT * FROM RecursiveCTE;在上面的示例中:•RecursiveCTE是递归公共表表达式的名称。
•column1, column2, ...是你要选择的列。
• 1 as level是递归的起始级别。
•<your_table>是你要查询的表。
•<your_condition>是用于选择起始行的条件。
•<join_condition>是用于连接递归成员与前一成员的条件。
•<additional_conditions>是可选的其他条件。
这个查询将从起始行开始,递归地连接符合条件的行,直到不再有符合条件的行为止。
level列用于跟踪递归的深度。
请注意,递归查询可能导致性能问题,因此在使用时要小心。
在某些数据库系统中,可能需要启用递归查询的特定选项。
sql语句递归查询使用注意事项
sql语句递归查询使用注意事项
1. 定义正确的递归条件:递归查询通常包含一个基本查询和一个递归查询。
基本查询用于获取初始数据,而递归查询用于获取与初始数据相关的更多数据。
在递归查询中,必须明确定义递归终止的条件,否则可能导致无限递归。
2. 使用适当的连接条件和过滤条件:递归查询通常需要指定连接条件和过滤条件,以确保查询结果与预期一致。
连接条件用于连接基本查询和递归查询的结果集,过滤条件用于限制递归查询的结果。
3. 考虑性能问题:递归查询可能涉及大量的数据和多次查询,因此性能是一个重要的考虑因素。
为了提高性能,可以使用索引、优化查询语句、使用临时表等技术。
4. 避免循环引用:在递归查询中,如果存在循环引用的情况,可能导致查询结果不准确或查询失败。
为了避免循环引用,可以使用限制递归深度的策略。
5. 注意数据完整性:递归查询可能导致无效或重复的数据,因此在编写递归查询语句时需要考虑数据完整性。
可以使用约束、触发器或其他数据验证机制来确保数据的完整性。
6. 适当使用递归查询:递归查询是强大的工具,但并不适用于所有情况。
在使用递归查询之前,需要仔细评估应用场景,确保递归查询是解决问题的最佳方法。
递归查询sql例子
递归查询sql例子递归查询在SQL中通常用于处理具有层次结构的数据,比如组织架构、地理位置等。
在SQL中,常用的递归查询语句是使用公共表表达式(CTE)和递归联接来实现的。
举个例子,假设我们有一个名为`employee`的表,其中包含员工的ID、姓名和直接上级的ID。
我们想要查询某个员工的所有下属,包括间接下属,可以使用递归查询来实现。
首先,我们需要创建一个递归查询的公共表表达式(CTE),例如`subordinates`,并在其中指定递归查询的初始条件和递归关系。
然后,我们使用递归联接将这个CTE与原始表连接起来,直到满足递归查询的终止条件为止。
以下是一个简单的示例:sql.WITH RECURSIVE subordinates AS (。
SELECT employee_id, employee_name, supervisor_id. FROM employee.WHERE employee_id = :input_employee_id -初始条件。
UNION ALL.SELECT e.employee_id, e.employee_name,e.supervisor_id.FROM employee e.INNER JOIN subordinates s ON e.supervisor_id =s.employee_id -递归关系。
)。
SELECT FROM subordinates;在这个例子中,我们首先创建了一个名为`subordinates`的CTE,指定了初始条件为特定员工的ID。
然后使用UNION ALL将初始条件的员工与直接下属连接起来,然后再次将直接下属与他们的下属连接起来,直到查询到所有的下属为止。
最后,我们从`subordinates`这个CTE中选择所有的员工信息。
这样就可以实现递归查询了。
需要注意的是,递归查询需要谨慎使用,因为如果数据量过大或者递归关系设计不当,可能会导致性能问题。
SQL语句递归查询WithAS查找所有子节点
SQL语句递归查询WithAS查找所有⼦节点create table #EnterPrise(Department nvarchar(50),--部门名称ParentDept nvarchar(50),--上级部门DepartManage nvarchar(30)--部门经理)insert into #EnterPrise select '技术部','总经办','Tom'insert into #EnterPrise select '商务部','总经办','Jeffry'insert into #EnterPrise select '商务⼀部','商务部','ViVi'insert into #EnterPrise select '商务⼆部','商务部','Peter'insert into #EnterPrise select '程序组','技术部','GiGi'insert into #EnterPrise select '设计组','技术部','yoyo'insert into #EnterPrise select '专项组','程序组','Yue'insert into #EnterPrise select '总经办','','Boss'--查询部门经理是Tom的下⾯的部门名称;with hgo as(select *,0 as rank from #EnterPrise where DepartManage='Tom'union allselect h.*,h1.rank+1 from #EnterPrise h join hgo h1 on h.ParentDept=h1.Department)select * from hgo/*Department ParentDept DepartManage rank--------------- -------------------- ----------------------- -----------技术部总经办 Tom 0程序组技术部 GiGi 1设计组技术部 yoyo 1专项组程序组 Yue 2*/--查询部门经理是GiGi的上级部门名称;with hgo as(select *,0 as rank from #EnterPrise where DepartManage='GiGi'union allselect h.*,h1.rank+1 from #EnterPrise h join hgo h1 on h.Department=h1.ParentDept)select * from hgo/*Department ParentDept DepartManage rank-------------------- ---------------------- ----------- -----------程序组技术部 GiGi 0技术部总经办 Tom 1总经办 Boss 2*/如果递归次数⼤于100,只需在与cte连接的sql 语句的最后加上option (maxrecursion 0) 即可.默认递归次数为100,设为0表⽰没有次数限制.。
sql写递归查询
sql写递归查询递归查询在SQL语言中可以使用`WITH RECURSIVE`语句实现,该语句能够实现在同一个查询中反复引用自身。
为了满足字数不少于6000字的要求,我们将分为以下几个部分来探讨递归查询。
1. 什么是递归查询递归查询是一种在关系型数据库中常用的查询技术,它可以用来在同一个查询中引用自身,从而实现对表或视图中的递归结构进行处理。
2. 递归查询的语法在SQL中,递归查询可以使用`WITH RECURSIVE`语句来定义。
基本语法如下:```sqlWITH RECURSIVE递归查询名称 (递归查询的列名1, 递归查询的列名2, ...)AS (-- 非递归查询非递归查询语句UNION ALL-- 递归查询递归查询语句)-- 最终查询SELECT * FROM 递归查询名称;```其中,递归查询语句中可以引用自身,直到满足递归终止条件为止。
3. 递归查询的应用场景递归查询在关系型数据库中有广泛的应用场景,例如组织架构、文件系统、树形结构等。
在这些场景中,通过递归查询可以方便地处理上下级关系、查询子节点或父节点等需求。
4. 递归查询的例子假设有下面这样一个表`Employee`,其中包含员工的ID、姓名和直属上级的ID。
```sqlCREATE TABLE Employee (ID INT,Name VARCHAR(50),ManagerID INT);INSERT INTO Employee (ID, Name, ManagerID)VALUES(1, 'John', NULL),(2, 'Mary', 1),(3, 'Peter', 1),(4, 'Alice', 2),(5, 'Bob', 3),(6, 'Tom', 4),(7, 'Sara', 5),(8, 'David', 6),(9, 'Lisa', 7),(10, 'Mike', 8);```现在需要查询员工的直属上级以及上级的上级,直到到达根节点为止。
sql中的递归
sql中的递归递归是一种在计算机科学中广泛使用的编程技术,它允许我们定义一个函数或过程,该函数或过程可以调用自身来解决问题。
在SQL中,我们可以使用递归来解决一些复杂的问题,如层次查询和树形结构的处理。
## 1. 什么是递归?递归是指在一个过程中,函数或者子程序通过调用自身的方式来解决问题的方法。
每次调用自身时,都会将问题规模缩小,直到达到基本情况,然后逐步返回结果。
## 2. SQL中的递归查询在SQL中,我们可以使用`WITH RECURSIVE`语句来创建递归查询。
这个语句首先定义了一个临时的结果集(称为公共表表达式),然后在这个结果集上进行递归操作。
递归查询的基本语法如下:```sqlWITH RECURSIVE recursive_table_name (column1, column2, ...)AS (-- 非递归部分:初始值SELECT ...FROM ...UNION ALL-- 递归部分:递归条件SELECT ...FROM ...JOIN recursive_table_name ON ...)SELECT ...FROM recursive_table_name;```- `recursive_table_name`是递归表的名称。
- `column1, column2, ...`是递归表中的列名。
- `UNION ALL`用于连接非递归部分和递归部分。
- 在递归部分,我们需要引用`recursive_table_name`来实现递归。
## 3. 示例:层级查询假设我们有一个员工表,每个员工有一个上级领导,我们想要获取所有的员工及其上级领导的信息。
这是一个典型的层次查询问题,可以使用递归来解决。
```sqlCREATE TABLE Employee (id INT PRIMARY KEY,name VARCHAR(50),manager_id INT,FOREIGN KEY (manager_id) REFERENCES Employee(id));INSERT INTO Employee VALUES (1, '张三', NULL);INSERT INTO Employee VALUES (2, '李四', 1);INSERT INTO Employee VALUES (3, '王五', 2);INSERT INTO Employee VALUES (4, '赵六', 2);INSERT INTO Employee VALUES (5, '孙七', 3);```现在,我们想要获取所有的员工及其上级领导的信息。
sql语句 递归
sql语句递归递归在SQL语句中主要用于解决树状结构的查询问题,可以通过递归查询获取树状结构的所有节点或者某个节点的所有子节点。
下面列举了10个使用递归的SQL语句示例。
1. 查询某个节点的所有子节点```sqlWITH RECURSIVE cte AS (SELECT id, name, parent_idFROM nodesWHERE id = :node_idUNION ALLSELECT n.id, , n.parent_idFROM nodes nINNER JOIN cte ON n.parent_id = cte.id)SELECT *FROM cte;```2. 查询某个节点的所有父节点```sqlWITH RECURSIVE cte AS (SELECT id, name, parent_idFROM nodesWHERE id = :node_idUNION ALLSELECT n.id, , n.parent_idFROM nodes nINNER JOIN cte ON n.id = cte.parent_id )SELECT *FROM cte;```3. 查询某个节点的所有祖先节点```sqlWITH RECURSIVE cte AS (SELECT id, name, parent_idFROM nodesWHERE id = :node_idUNION ALLSELECT n.id, , n.parent_idFROM nodes nINNER JOIN cte ON n.id = cte.parent_id)SELECT *FROM cteWHERE id <> :node_id;```4. 查询某个节点的所有子孙节点的数量```sqlWITH RECURSIVE cte AS (SELECT id, parent_idFROM nodesWHERE id = :node_idUNION ALLSELECT n.id, n.parent_idFROM nodes nINNER JOIN cte ON n.parent_id = cte.id )SELECT COUNT(*) AS descendant_count FROM cte;```5. 查询某个节点的所有子孙节点的深度```sqlWITH RECURSIVE cte AS (SELECT id, parent_id, 1 AS depthFROM nodesWHERE id = :node_idUNION ALLSELECT n.id, n.parent_id, cte.depth + 1FROM nodes nINNER JOIN cte ON n.parent_id = cte.id)SELECT MAX(depth) AS max_depthFROM cte;```6. 查询某个节点的所有子孙节点的路径```sqlWITH RECURSIVE cte AS (SELECT id, name, parent_id, CAST(name AS VARCHAR(1000)) AS pathFROM nodesWHERE id = :node_idUNION ALLSELECT n.id, , n.parent_id, CONCAT(cte.path, ' > ',)FROM nodes nINNER JOIN cte ON n.parent_id = cte.id)SELECT *FROM cte;```7. 查询某个节点的所有子节点的数量及其父节点名称```sqlWITH RECURSIVE cte AS (SELECT id, name, parent_idFROM nodesWHERE id = :node_idUNION ALLSELECT n.id, , n.parent_idFROM nodes nINNER JOIN cte ON n.parent_id = cte.id)SELECT COUNT(*) AS child_count, AS parent_name FROM cteGROUP BY ;```8. 查询某个节点的所有父节点的数量及其子节点名称```sqlWITH RECURSIVE cte AS (SELECT id, name, parent_idFROM nodesWHERE id = :node_idUNION ALLSELECT n.id, , n.parent_idFROM nodes nINNER JOIN cte ON n.id = cte.parent_id)SELECT COUNT(*) AS parent_count, AS child_name FROM cteGROUP BY ;```9. 查询某个节点的所有子节点的数量及其路径```sqlWITH RECURSIVE cte AS (SELECT id, name, parent_id, CAST(name AS VARCHAR(1000)) AS pathFROM nodesWHERE id = :node_idUNION ALLSELECT n.id, , n.parent_id, CONCAT(cte.path, ' > ', )FROM nodes nINNER JOIN cte ON n.parent_id = cte.id)SELECT COUNT(*) AS child_count, pathFROM cteGROUP BY path;```10. 查询某个节点的所有父节点的数量及其路径```sqlWITH RECURSIVE cte AS (SELECT id, name, parent_id, CAST(name AS VARCHAR(1000)) AS pathFROM nodesWHERE id = :node_idUNION ALLSELECT n.id, , n.parent_id, CONCAT(, ' > ',cte.path)FROM nodes nINNER JOIN cte ON n.id = cte.parent_id)SELECT COUNT(*) AS parent_count, pathFROM cteGROUP BY path;```这些示例展示了递归在SQL语句中的应用,通过递归可以实现对树状结构的灵活查询和分析。
SQL递归查询(withas)
SQL递归查询(withas)with cte as(select Id,Pid,DeptName,0as lvl from Departmentwhere Id =2union allselect d.Id,d.Pid,d.DeptName,lvl+1from cte c inner join Department don c.Id = d.Pid)select*from cte1 表结构Id Pid DeptName----------- ----------- --------------------------------------------------0 总部1 研发部1 测试部1 质量部2 ⼩组12 ⼩组23 测试13 测试25 前端组5 美⼯2 查询结果查部门ID=2的所有下级部门和本级Id Pid DeptName lvl----------- ----------- -------------------------------------------------- -----------1 研发部 02 ⼩组1 12 ⼩组2 15 前端组 25 美⼯ 2(5 ⾏受影响)3 原理(摘⾃⽹上) 递归CTE最少包含两个查询(也被称为成员)。
第⼀个查询为定点成员,定点成员只是⼀个返回有效表的查询,⽤于递归的基础或定位点。
第⼆个查询被称为递归成员,使该查询称为递归成员的是对CTE名称的递归引⽤是触发。
在逻辑上可以将CTE名称的内部应⽤理解为前⼀个查询的结果集。
递归查询没有显式的递归终⽌条件,只有当第⼆个递归查询返回空结果集或是超出了递归次数的最⼤限制时才停⽌递归。
是指递归次数上限的⽅法是使⽤MAXRECURION。
sql中recursive的用法
sql中recursive的用法
在SQL中,递归(recursive)是一种功能,它允许我们在查询中引用同一张表的数据,以便能够处理层次结构的数据或者进行自引用的操作。
递归查询通常使用`WITH`语句和`RECURSIVE`关键字来实现。
首先,我们使用`WITH RECURSIVE`语句来定义递归查询的公共表表达式(CTE)。
CTE是一个临时的命名查询结果,它允许我们在后续的查询中引用它。
`WITH RECURSIVE`语句中的`RECURSIVE`关键字表示这是一个递归查询。
接下来,在`WITH RECURSIVE`语句中,我们定义递归查询的初始查询(也称为基本查询),然后定义递归查询的递归部分。
递归部分包括递归的选择部分和递归的连接部分。
在递归查询的选择部分,我们定义了递归查询的终止条件,也就是递归查询应该何时停止。
这通常是一个简单的条件,用于指示递归查询已经达到了结束状态。
在递归查询的连接部分,我们定义了如何从递归查询的上一次
迭代中生成下一次迭代的数据。
这通常涉及将递归查询的结果与原始表进行连接,以便生成新的数据。
总的来说,递归在SQL中通常用于处理层次结构的数据,比如组织架构、树形结构等。
通过递归查询,我们可以轻松地处理这些数据,并且能够在单个查询中完成复杂的操作。
递归查询是SQL中非常强大和灵活的功能,但也需要谨慎使用,以避免无限循环和性能问题。
