[SQL Server] TSQL实现SQL Server中CTE 递归查询

2023-11-08

参考博客:https://www.cnblogs.com/ljhdo/p/4580347.html

简介

递归查询主要应用于层级结构表的查询:

  • 叶节点-> 根节点的查询
  • 根节点-> 叶节点的查询

递归查询必须满足的条件

初始条件

递归查询至少包含两个子查询两个子查询使用union all,求并集

  1. 第一个子查询称作定点(Anchor)子查询:定点查询只是一个返回有效表的查询,用于设置递归的初始值
  2. 第二个子查询称作递归子查询:触发递归查询,实际上是递归子查询调用递归子查询

终止条件

  • 递归查询没有显式的递归终止条件,
  • 只有当递归子查询返回空结果集(没有数据行返回)或是超出了递归次数的最大限制时,才停止递归
  • 默认的递归查询次数是100,可以使用查询提示(hint):MAXRECURSION 控制递归的最大次数:OPTION( MAXRECURSION 16);如果允许无限制的递归次数,使用查询提示:option(maxrecursion 0);当递归查询达到指定或默认的 MAXRECURSION 数量限制时,SQL Server将结束查询并返回错误,如下:
The statement terminated. The maximum recursion 100 has been exhausted before statement completion.
  • 事务执行失败,该事务包含的所有操作都被回滚。在产品环境中,慎用maxrecursion 查询提示,推荐通过 where 条件限制递归的次数。

递归调用表达式

  1. 定点子查询设置CTE的初始值,即CTE的初始值Set0递归调用的子查询过程:递归子查询调用递归子查询
  2. 递归子查询第一次调用CTE名称,CTE名称是指CTE的初始值Set0第一次执行递归子查询之后,CTE名称是指结果集Set1
  3. 递归子查询第二次调用CTE名称,CTE名称是指Set1,第二次执行递归子查询之后,CTE名称是指结果集Set2;
  4. 在第N次执行递归子查询时,CTE名称是指Set(N-1),递归子查询都引用前一个递归子查询的结果集;
  5. 如果递归子查询返回空数据行,或超出递归次数的最大限制,停止递归

递归查询示例

创建测试数据

创建一张临时表manager_user,其中ManagerID是UserID的父节点,UserID是ManagerID的子节点

create table #manager_user
(
    UserID int,
    ManagerID int,
    Name Nvarchar(10)
)

insert into #manager_user
select 1,-1,N'Boss'
union all
select 11,1,N'A1'
union all
select 12,1,N'A2'
union all
select 13,1,N'A3'
union all
select 111,11,N'B1'
union all
select 112,11,N'B2'
union all
select 121,12,N'C1'

其结果展示如下图所示:
在这里插入图片描述

查询每个User的的直接上级Manager

  1. 查询ManagerID=-1,作为root node,这是递归查询的起始点。
  2. 迭代公式是 union all 下面的查询语句。在查询语句中调用中cte,而查询语句就是cte的组成部分,即 “自己调用自己”,这就是递归的真谛所在。所谓迭代,是指每一次递归都要调用上一次查询的结果集,Union ALL是指每次都把结果集并在一起。
  3. -N,迭代公式利用上一次查询返回的结果集执行特定的查询,直到CTE返回null 或达到最大的迭代次数,默认值是32。最终的结果集是迭代公式返回的各个结果集的并集,求并集是由Union All 子句定义的,并且只能使用Union ALL。
with cte as
(
select UserID,ManagerID,name,name as ManagerName
from #manager_user
where ManagerID=-1

union all

select c.UserID,c.ManagerID,c.Name,p.name as ManagerName
from cte P
inner join #manager_user c
    on p.UserID=c.ManagerID
)
select UserID,ManagerID,Name,ManagerName
from cte
order by UserID

其结果展示为:
在这里插入图片描述

查询路径,在层次结构中查询子节点到父节点的path

with cte as
(
select UserID,ManagerID,name,cast(name as nvarchar(max)) as ReportPath
from #manager_user
where ManagerID=-1

union all
select c.UserID,c.ManagerID,c.Name,c.name+'->'+p.ReportPath as ReportPath
from cte P
inner join #manager_user c
    on p.UserID=c.ManagerID
)
select UserID,ManagerID,Name,ReportPath
from cte
order by UserID

其结果展示为:
在这里插入图片描述

实现由父级向子级的查询

要想获取ManagerID的所有UserID等信息,必须使用递归查询

下列sql展示的是ManagerId =1的所有相关子节点

with cte(UserId,ManagerID,Name) as
(
select * 
from #manager_user
where UserId=1

union all
select h.* 
from #manager_user h
inner join cte c on h.ManagerID=c.UserId 
--where c.UserId!=h.UserId 
)
select *
from cte
order by ManagerID

其查询结果为:
在这里插入图片描述

如果要查看向内递归到多少level,可以使用派生列

下列sql展示的是ManagerId =1的所有相关子节点以及递归到多少level

with cte(UserId,ManagerId,Name,Level) as
(
select UserId,ManagerId,Name,0 as Level
from #manager_user 
where UserId=1

union all
select h.UserId,h.ManagerId,h.Name,c.Level+1 as Level
from #manager_user h
inner join cte c on h.ManagerId=c.UserId 
--where c.UserId!=h.UserId
)
select *
from cte
order by ManagerId

其结果展示为:
在这里插入图片描述

由子级向父级的递归查询

下列sql展示的是UserId =121的所有相关父节点

with cte as
(
select UserId,ManagerId,name
from #manager_user
where UserId= 121

union all
select h.UserId,h.ManagerId,h.name
from #manager_user h
inner join cte c on h.UserId=c.ManagerId
)
select UserId,ManagerId,name
from cte
order by ManagerId

其结果展示为:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[SQL Server] TSQL实现SQL Server中CTE 递归查询 的相关文章

  • SQL Server 上的语法错误

    这可能是一个愚蠢的语法错误 但我只是继续阅读我的程序 但我无法弄清楚我的错误在哪里 消息 156 第 15 级 状态 1 第 41 行关键字附近的语法不正确 为了 这是我的代码 alter procedure LockReservation
  • 使用 postgres 和 node js 在单个语句中执行多个查询

    我需要在像这样的单个语句中执行插入和删除查询 INSERT INTO COMPANY ID NAME VALUES 1 Paul DELETE FROM COMPANY WHERE ID 12 这是我用于执行查询的 node js 代码 p
  • POINT 列上的 MySQL INSERT/UPDATE

    我正在尝试用我国家的地理位置填充我的数据库 我的一张表有 4 个字段 ID PK 纬度 经度和地理点 EDIT SCDBs Punto Geografico SET lat 18 469692 SET lon 63 93212 SET g
  • 如何在mysql中选择具有相同值集的列?

    我的桌子是 patients pid name city disease did dname has disease did pid 我想列出具有相同疾病组的患者 pid 和 did 分别是患者和疾病表中的主键 并且是 has diseas
  • 在 PL/SQL 中将绑定变量与动态 SELECT INTO 子句结合使用

    我有一个关于 PL SQL 中的动态 SQL 语句中可以使用绑定变量的问题 例如 我知道这是有效的 CREATE OR REPLACE FUNCTION get num of employees p loc VARCHAR2 p job V
  • 给定“java.sql.SQLIntegrityConstraintViolationException”是否可以确定错误的列

    鉴于我有一个类型为 java sql SQLIntegrityConstraintViolationException 的异常 是否可以以编程方式确定错误的列 或多列 我问这个问题是因为我想将错误映射回客户端的数据模型以指示错误的字段 例如
  • 如何查找当前数据库类型

    我们有一个 SQL 脚本可以在多种类型的数据库上执行 是否可以获取正在执行 SQL 脚本的当前数据库的类型 注意 我们不能使用非标准 SQL 即 TSQL 等 不 ANSI SQL 中没有任何关于确定数据库供应商的内容
  • 如何在 DB2 AS/400 中将小数字段转换为日期字段?

    我有一个 DECIMAL 字段 其中包含 AS400 格式的日期 1100614 我努力了 cast MYDATE as DATE 但我无法将 DECIMAL 转换为 DATE 而 DATE MYDATE 返回空值 如何将此字段转换为日期字
  • Linq To SQL - 拥有和分组依据

    我下面这个查询工作正常 不过我想使用 Linq 来实现它 select u ID u NAME from Task t join BuildingUser bu ON bu ID BUILDING t ID BUILDING join Us
  • 需要按天分割日期时间范围

    我有一个需要根据日期时间拆分的表 输入表 ID Start End A 2019 03 04 23 18 04 2019 03 04 23 21 25 A 2019 03 04 23 45 05 2019 03 05 00 15 14 所需
  • PostgreSQL 中“-”处或附近的语法错误

    我正在尝试运行查询来更新用户密码 alter user dell sys with password Pass 133 但因为 它给了我这样的错误 ERROR syntax error at or near LINE 1 alter use
  • Postgresql 一张表的多个计数

    我想从表中的两列中获得这些列中值的统一计数 例如 两列是 表 报告 type place one home two school three work four cafe five friends six mall one work one
  • Oracle:如何获取刚刚插入的行的序列号?

    如何获取刚刚插入的行的序列号 插入 返回 declare s2 number begin insert into seqtest2 x values aaa returning seq into s2 dbms output put lin
  • SQL 2008全文索引填充延迟

    我的经理说 在基础表数据更改后 可能需要一段时间才能更新全文搜索索引 例如 如果我有一张桌子Products有一个柱子Description我更新了该描述 然后我可能需要一些时间才能搜索该新描述 真的吗 这需要多长时间 SQL 2008 对
  • 如何通过子 POJO 的属性过滤复合 ManyToMany POJO?

    我有两个像这样的房间实体 Entity public class Teacher implements Serializable PrimaryKey autoGenerate true public int id ColumnInfo n
  • 快速查询最新记录的方法?

    我有一张这样的表 USER PLAN START DATE END DATE 1 A 20110101 NULL 1 B 20100101 20101231 2 A 20100101 20100505 在某种程度上 如果END DATE i
  • 删除数据库中的行后如何重新排序ID

    我正在使用 C 来制作具有 sql 数据库的程序 在数据库中我有一个名为Workers 它有一个自动增量和主键ID column 当我删除一条记录时 ID 之间会出现间隙 删除记录后如何重新排序 ID UPDATE 我要做的就是找到记录后将
  • 我不断收到错误“关系 [TABLE] 不存在”

    我一直在尝试查询数据库中的两个表 在服务器资源管理器中 我可以看到两个表 甚至可以看到其中的列 我们将它们称为 Schema table1 和 Schema table2 其中 Schema 的第一个字母大写 我尝试运行以下查询 selec
  • 如何通过SQL查询检查是否有JSON函数?

    有SQL 2016 中的 JSON 函数 https learn microsoft com en us sql t sql functions json functions transact sql例如 JSON VALUE JSON Q
  • 如何获取自定义订单的结果? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 代替ASC or DESC 我希望我的查询结果采用特定的自定义顺序 例如 如果我想要的结果不是 A B C D 而是 P A L H 该怎么

随机推荐

  • 人体活动识别总结

    人体活动识别 活动识别过程 数据采集 数据预处理 窗口分割 特征提取 特征选择 活动分类 面临问题 人类活动识别 HAR 仍有许多问题促使新技术的发展 以提高在更现实的条件下的准确性 其中一些挑战是 1 要度量的属性选择 2 便携的 不显眼
  • 3D开发-PhotoScan 模型生成

    PhotoScan是一款图片转3D模型软件 需要商业license 其图片转3D模型效果非常好 是一款基于影响自动生成高质量三维模型的优秀软件 这对于3D建模需求来说实在是一把利器 图片转3D模型操作 Step1 选择工作流程 Step2
  • 虚拟现实(VR)在医疗保健中的5种应用

    医疗保健中的VR虚拟现实 虚拟现实的由来已久 18世纪 法国的医生使用布制的分娩模拟器向助产师和外科医生教授医学技术 在20世纪60年代初 医生一边对心肺复苏学员口述心肺复苏的技巧 一边使用一家塑料玩具厂家制造的塑料娃娃现场演示胸部按压和人
  • 安全(四):CSRF攻击

    csrf获取的不是用户的所有权限 获取的是用户在修改东西的时候 通过url权限修改信息 查看这里
  • MySQL-面试题

    第六章 决胜秋招 Section A 练习一 各部门工资最高的员工 难度 中等 创建Employee 表 包含所有员工信息 每个员工有其对应的 Id salary 和 department Id Id Name Salary Departm
  • 已知树的中序序列和先序/后序序列,求树的结构?

    已知树的中序序列和先序 后序序列 求树的结构 这类问题比较经典了 刚好CSDN上有人问起 所以自己写了一个递归算法 根据中序和先序 后序 建立树结构 这里需要说明的是 必须要知道中序序列 先序和后序可选的情况下才能推导出树结构 只知道后序先
  • Springboot毕设项目二手手机回收系统2r40d(java+VUE+Mybatis+Maven+Mysql)

    Springboot毕设项目二手手机回收系统2r40d java VUE Mybatis Maven Mysql 项目运行 环境配置 Jdk1 8 Tomcat8 5 Mysql HBuilderX Webstorm也行 Eclispe I
  • selenium三种等待方式详解

    一 场景 我们在做WEB自动化时 一般要等待页面元素加载完成后 才能执行操作 否则会报找不到元素的错误 这样就要求我们在有些场景下加等待时间 二 强制等待 1 利用time模块的sleep方法来实现 最简单粗暴的方法 2 不管浏览器是否加载
  • 关于RecyclerView一系列问题汇总

    今天主要分享的主要是使用recyclerview添加item 删除item的一些问题的汇总 后续持续更新 开发多年一直在使用BaseRecyclerViewAdapterHelper这个库 就拿这个来举例 添加item mAdapter a
  • 解决 ModuleNotFoundError: No module named 'pip'

    今天 安装其它python包时 提示说 pip 10 0 1可用 就更新了一下 但是 更新过程中出现了错误 如图所示 因为这个错误导致 pip找不到 可以首先执行 python m ensurepip 然后执行 python m pip i
  • 【Redis】五种数据结构的常用命令,及多种应用场景示例

    Redis 是一个开源 高级的键值存储和一个适用的解决方案 用于构建高性能 可扩展的 Web 应用程序 Redis 也被作者戏称为数据结构服务器 这意味着使用者可以通过一些命令 基于带有 TCP 套接字的简单 服务器 客户端 协议来访问一组
  • 电池并联防止接反电路设计

    缘由两节电池并联电路如何实现可靠的防反接效果 电源技术论坛 电子技术论坛 广受欢迎的专业电子论坛
  • 关于静态变量与非静态变量的区别

    public class Cluster private static String id 与 public class Cluster private String id 的不同 前者中定义的是静态变量id 这个变量在类加载 不是new
  • 原生安卓继承uniapp后执行自定义的applicaiton与activity(实现双击退出按钮监听)

    一 自定义application 乱起八糟的不用管 1 MyApplication java public class MyApplication extends DCloudApplication Override public void
  • 【QT 网络云盘客户端】——实现文件属性窗口

    目录 文件属性对话框 设置字体样式 获取文件的信息 显示文件属性对话框 当我们点击文件中的属性 则会弹出一个属性对话框 实现过程 0 设置 属性 菜单项的槽函数 1 鼠获取鼠标选中的QListWidgetItem 它包含 图标和文件名 2
  • Java高级开发的50个性能优化

    在JAVA程序中 性能问题的大部分原因并不在于JAVA语言 而是程序本身 养成良好的编码习惯非常重要 能够显著地提升程序性能 1 尽量在合适的场合使用单例 使用单例可以减轻加载的负担 缩短加载的时间 提高加载的效率 但并不是所有地方都适用于
  • 李沐老师动手学深度学习v2中 LeNet实现中遇到的运行报错问题以及无法显示动态图片问题

    问题一 RuntimeError DataLoader worker pid s 4088 9912 220 exited unexpectedly报错问题 报错原因 Windows不支持多线程 在运行下面这句时调用了get dataloa
  • redis单线程模型为什么这么高效

    一 为什么Redis是单线程的 Redis 是基于内存的操作 而CPU 不是 Redis 的瓶颈 Redis 的瓶颈最有可能是机器内存的 大小或者网络带宽 同时 单线程的实现更加简单和经济 采用单线程可以使指令串行 不用额外 维护锁机制 避
  • vs创建c语言项目

    vs创建c语言项目 已知用c 做一些简单的开发 以前虽然也捅咕过C和C 但是好久不上手了 现在用VS都不知道怎么创建C项目 首先打开VS程序 选择新建一个项目 然后在里面选择C 新建win32控制台程序 下面的哪些名字和路径 改了项目名就行
  • [SQL Server] TSQL实现SQL Server中CTE 递归查询

    参考博客 https www cnblogs com ljhdo p 4580347 html 简介 递归查询主要应用于层级结构表的查询 叶节点 gt 根节点的查询 根节点 gt 叶节点的查询 递归查询必须满足的条件 初始条件 递归查询至少