今天用到了sql的递归查询。递归查询是CTE语句with xx as(....)实现的。

假如表Category数据如下。

我们想查找机枪这个子分类极其层次关系(通过子节点,查询所有层级节点)。以下是查询语句

WITH tt AS (

SELECT CategoryId,Name,Parent,0 level  FROM dbo.Category WHERE CategoryId=15  --定位点成员
UNION ALL
SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN tt ON tt.Parent=c.CategoryId --递归成员 ) SELECT * FROM tt

 执行结果

CTE递归说明:

上面的脚本,我注明了定位点成员,和递归成员。

定位点成员形成了查询的基本结果集。其实就是你用于查询的"引子"数据。在递归cte开始执行时,第一次执行,会先执行定位成员,并得到寄出结果集。

递归成员是每次递归执行的语句。个人意淫,每次递归时,是把上一次递归查询得出的结果集传递给递归语句,并继续执行递归

在递归时,如果上一次查询没有返回结果集,则终止递归。(这点让我纠结很久,因为没有显示的著名何时结束递归~)

意淫的执行步骤--------------------

首先执行定位成员:

SELECT CategoryId,Name,Parent,0 level  FROM dbo.Category WHERE CategoryId=46

并得到了结果集:

然后执行第一次递归:

SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN tt ON tt.Parent=c.CategoryId

执行递归时,join了 cte 语句本身,就是tt,join里的语句跟with as里的语句一样。其实语句可以意淫成酱紫

SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN
(
--SELECT CategoryId,Name,Parent,0 level FROM dbo.Category WHERE CategoryId=15 华丽的忽略掉了
--UNION ALL 华丽的忽略掉了
SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN tt ON tt.Parent=c.CategoryId --我们继续递归~ )tt ON tt.Parent=c.CategoryId

这次递归可以拆分成两个操作,查询结果和继续递归。

1.因为是第一次递归,所以将执行定位成员得出的结果集带入,进行查询。其实执行的是酱紫

SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN
(
SELECT CategoryId,Name,Parent,0 level FROM dbo.Category WHERE CategoryId=46 )tt ON tt.Parent=c.CategoryId

发现有结果:

则继续进行递归:

递归时语句还是酱紫:

SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN
(
--SELECT CategoryId,Name,Parent,0 level FROM dbo.Category WHERE CategoryId=15 华丽的忽略掉了
--UNION ALL 华丽的忽略掉了
SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN tt ON tt.Parent=c.CategoryId --我们继续递归 )tt ON tt.Parent=c.CategoryId

这次递归查询,所用的结果集是上次递归查询得出的(不再是定位成员的结果集了)。就是用的下面这个结果集

执行语句是酱紫的

SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN
(
SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN
(
SELECT CategoryId,Name,Parent,0 level FROM dbo.Category WHERE CategoryId=46 )tt ON tt.Parent=c.CategoryId
)tt ON tt.Parent=c.CategoryId

第一层join的数据是上次递归查询的语句。

发现有结果:

ok继续递归吧

继续上面的步骤,带入上次查询的结果集进行查询。

执行语句其实是酱紫:

SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN
(
SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN
(
SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN
(
SELECT CategoryId,Name,Parent,0 level FROM dbo.Category WHERE CategoryId=46 )tt ON tt.Parent=c.CategoryId
)tt ON tt.Parent=c.CategoryId
)tt ON tt.Parent=c.CategoryId

得出的结果集:

啥也木有,终止递归。

然后用union all 把每次递归的结果集合起来。得出了最终的查询结果。

这个步骤是意淫的,我还设想了其他的方式。但在终止递归上都存在问题,所以最终把文章写成酱紫。

参考文章:https://www.cnblogs.com/youngmin/p/6256478.html

SQL 递归查询,意淫CTE递归的执行步骤的更多相关文章

  1. SQL Server中公用表表达式 CTE 递归的生成帮助数据,以及递归的典型应用

    本文出处:http://www.cnblogs.com/wy123/p/5960825.html 我们在做开发的时候,有时候会需要一些帮助数据,必须需要连续的数字,连续间隔的时间点,连续的季度日期等等 ...

  2. TSql CTE 递归原理探究

    CTE是如何进行递归的?产生递归的条件有三个,分别是 初始值 自身调用自身 结束递归的条件 1,示例代码 ;with cte as ( as jd union all as jd from cte ) ...

  3. 【转】sql递归查询问题

    原文链接地址http://www.cnblogs.com/sweting/archive/2009/06/08/1498483.html 在工作中遇到一个问题,是需要sql递归查询的.不懂,于是到cs ...

  4. SQL递归查询(with as)

    SQL递归查询(with cte as) with cte as(    select Id,Pid,DeptName,0 as lvl from Department    where Id = 2 ...

  5. SQL Server封闭掉 触发器递归

    SQL Server关闭掉 触发器递归SQL Server  是有一个开关, 可以关闭掉 触发器递归的.EXEC sp_dboption '数据库名字', 'recursive triggers', ...

  6. SQL语句在查询分析器中可以执行,代码中不能执行

    问题:SQL语句在查询分析器中可以执行,代码中不能执行 解答:sql中包含数据库的关键字,将关键字用[]括起来,可以解决. 后记:建数据库的时候尽量避免使用关键字. 例子: sql.Format(&q ...

  7. sql语句or与union all的执行效率比较

    看到一篇文章是讲sql语句or与union all的执行效率比较的,以前没怎么注意这个问题,感觉文章写的不错,转来一看. 文章原链接:http://www.cunyoulu.com/zhuanti/q ...

  8. SQL语句在数据库中是如何执行的

    第一步:应用程序把查询SQL语句发给服务器端执行 我们在数据层执行SQL语句时,应用程序会连接到相应的数据库服务器,把SQL语句发送给服务器处理. 第二步:服务器解析请求的SQL语句 SQL计划缓存, ...

  9. jQuery使用伪递归重复执行动画

    使用setInterval()来重复执行动画,会因为动画执行过程的时候,setInterval()的时间依然是在走的,所以会导致动画的调用时间不理想,因此只能使用递归来重复执行动画. // 首页LOG ...

随机推荐

  1. 【VS开发】Return与Exit的区别

    1. exit用于结束正在运行的整个程序,它将参数返回给OS,把控制权交给操作系统:而return 是退出当前函数,返回函数值,把控制权交给调用函数. 2. exit是系统调用级别,它表示一个进程的结 ...

  2. JAVA连接Sql-Server教程

    一.下载相应的版本的jar文件(官网:https://docs.microsoft.com/zh-cn/sql/connect/jdbc/system-requirements-for-the-jdb ...

  3. idea设置方法注释

    1. File-->Settings-->Editor-->Live Templates 1.1 新建Template Group: 命名为 methodNote 1.2 在meth ...

  4. 对于大于等于3的整数n,在区间【n,3/2 * n】中一定存在一个素数

    对于大于3的整数n,在区间[n,3/2 * n]中一定存在一个素数

  5. vim bundle安装

    一.准备工作 安装Git(因为下面我们选择的插件管理器需要使用到它)安装其他插件前首先需要选择一个Vim插件管理器,我这里选择的是Vundle,Vundle的工作过程中需要通过Git自动从远程创库同步 ...

  6. React Native 中 component 生命周期

    React Native 中 component 生命周期 转自 csdn 子墨博客  http://blog.csdn.net/ElinaVampire/article/details/518136 ...

  7. 剑指offer49:把字符串转换成整数

    1 题目描述 将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数. 数值为0或者字符串不 ...

  8. LeetCode 328——奇偶链表(JAVA)

    给定一个单链表,把所有的奇数节点和偶数节点分别排在一起.请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性. 请尝试使用原地算法完成.你的算法的空间复杂度应为 O(1),时 ...

  9. 第十四章 ZYNQ TIMER定时器中断

      上篇文章实现了了PS接受来自PL的中断,本片文章将在ZYNQ的纯PS里实现私有定时器中断.每隔一秒中断一次,在中断函数里计数加1,通过串口打印输出. 本文所使用的开发板是Miz702 PC 开发环 ...

  10. Delphi编译器属性(特别修饰符Ref,Unsafe,Volatile,Weak)

    1 Refdelphi中常量参数就像一个本地常量,或者说只读变量.常量参数与值参数类似,除了不能在过程或函数体内给常量参数赋值,并且不能将常量参数传给另一个var类型参数.(但是,如果你常量参数传递的 ...