在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询,本文详细介绍CTE递归调用的特性和使用示例,递归查询主要用于层次结构的查询,从叶级(Leaf Level)向顶层(Root Level)查询,或从顶层向叶级查询,或递归的路径(Path)。

一,递归查询原理

CTE的递归查询必须满足三个条件:初始条件,递归调用表达式,终止条件,CTE 递归查询的伪代码如下:

WITH cte_name ( column_name [,...n] )
AS
(
--Anchor member is defined
CTE_query_definition
UNION ALL
--Recursive member is defined referencing cte_name
CTE_query_definition
)
-- Statement using the CTE
SELECT *
FROM cte_name

1,递归查询至少包含两个子查询:

  • 第一个子查询称作定点(Anchor)子查询:定点查询只是一个返回有效表的查询,用于设置递归的初始值;
  • 第二个子查询称作递归子查询:该子查询调用CTE名称,触发递归查询,实际上是递归子查询调用递归子查询;
  • 两个子查询使用union all,求并集;

2,CTE的递归终止条件

递归查询没有显式的递归终止条件,只有当递归子查询返回空结果集(没有数据行返回)或是超出了递归次数的最大限制时,才停止递归。

默认的递归查询次数是100,可以使用查询提示(hint):MAXRECURSION 控制递归的最大次数:OPTION( MAXRECURSION 16);如果允许无限制的递归次数,使用查询提示:option(maxrecursion 0);当递归查询达到指定或默认的 MAXRECURSION 数量限制时,SQL Server将结束查询并返回错误,如下:

The statement terminated. The maximum recursion 10 has been exhausted before statement completion.

事务执行失败,该事务包含的所有操作都被回滚。在产品环境中,慎用maxrecursion 查询提示,推荐通过 where 条件限制递归的次数。

3,递归步骤

step1:定点子查询设置CTE的初始值,即CTE的初始值Set0;

递归调用的子查询过程:递归子查询调用递归子查询;

step2:递归子查询第一次调用CTE名称,CTE名称是指CTE的初始值Set0,第一次执行递归子查询之后,CTE名称是指结果集Set1;

step3:递归子查询第二次调用CTE名称,CTE名称是指Set1,第二次执行递归子查询之后,CTE名称是指结果集Set2;

step4:在第N次执行递归子查询时,CTE名称是指Set(N-1),递归子查询都引用前一个递归子查询的结果集;

Step5:如果递归子查询返回空数据行,或超出递归次数的最大限制,停止递归;

二,递归查询示例(员工职称)

1,创建测试数据

ManagerID是UserID的父节点,这是一个非常简单的层次结构模型。

use tempdb
go create table dbo.dt_user
(
UserID int,
ManagerID int,
Name Nvarchar()
) insert into dbo.dt_user
select ,-,N'Boss'
union all
select ,,N'A1'
union all
select ,,N'A2'
union all
select ,,N'A3'
union all
select ,,N'B1'
union all
select ,,N'B2'
union all
select ,,N'C1'

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

;with cte as
(
select UserID,ManagerID,name,name as ManagerName
from dbo.dt_user
where ManagerID=- union all
select c.UserID,c.ManagerID,c.Name,p.name as ManagerName
from cte P
inner join dbo.dt_user c
on p.UserID=c.ManagerID
)
select UserID,ManagerID,Name,ManagerName
from cte
order by UserID

step1:查询ManagerID=-1,作为root node,这是递归查询的起始点。

step2:迭代公式是 union all 下面的查询语句。在查询语句中调用中cte,而查询语句就是cte的组成部分,即 “自己调用自己”,这就是递归的真谛所在。

所谓迭代,是指每一次递归都要调用上一次查询的结果集,Union ALL是指每次都把结果集并在一起。

step3-N,迭代公式利用上一次查询返回的结果集执行特定的查询,直到CTE返回null 或达到最大的迭代次数,默认值是32。最终的结果集是迭代公式返回的各个结果集的并集,求并集是由Union All 子句定义的,并且只能使用Union ALL。

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

;with cte as
(
select UserID,ManagerID,name,cast(name as nvarchar(max)) as ReportPath
from dbo.dt_user
where ManagerID=- union all
select c.UserID,c.ManagerID,c.Name,c.name+'->'+p.ReportPath as ReportPath
from cte P
inner join dbo.dt_user c
on p.UserID=c.ManagerID
)
select UserID,ManagerID,Name,ReportPath
from cte
order by UserID

查询结果如下截图:

三,递归查询示例(行政区划)

1,需求模拟

在TSQL中实现层次结构,例如有这样一种数据结构,省,市,县,乡,村,如何使用一张表表示这种数据结构,并且允许是不对称的,例如,上海市是个直辖市,没有省份。

create table dbo.hierarchy
(
ID int not null primary key,
--type int not null,
ParentID int not null,
name varchar() not null
)

type表示类型,可以设置:省,Type是1;市,type是2,以此类推。

ParentID标识的是父级ID,例如信阳市的ParentID是河南省的ID。

2,插入测试数据

测试数据格式说明了归属关系,博主懒,去掉type字段。

insert into dbo.hierarchy
values(,,'河南省')
,(,,'信阳市'),(,,'淮滨县'),(,,'芦集乡'),(,,'邓湾乡'),(,,'台头乡'),(,,'谷堆乡')
,(,,'固始县'),(,,'李店乡')
,(,,'息县'),(,,'关店乡')
,(,,'安阳市'),(,,'滑县'),(,,'老庙乡')
,(,,'南阳市'),(,,'方城县')
,(,,'驻马店市'),(,,'正阳县') select *
from dbo.hierarchy
order by ParentID

3,实现由父级向子级的查询

由于实际的数据可能有很多,所以,要想获取河南省下的所有市,县,乡,村等信息,必须使用递归查询

;with cte(Id,ParentID,Name) as
(
select *
from dbo.hierarchy
where id= union all
select h.*
from dbo.hierarchy h
inner join cte c on h.ParentID=c.id
--where c.id!=h.ID
)
select *
from cte
order by ParentID

如果要查看向内递归到多少level,可以使用派生列,level=0是省level,level=1是市level,依次类推。

;with cte(Id,ParentID,Name,Level) as
(
select ID,ParentID,Name, as Level
from dbo.hierarchy
where id= union all
select h.ID,h.ParentID,h.Name,c.Level+ as Level
from dbo.hierarchy h
inner join cte c on h.ParentID=c.id
--where c.id!=h.ID
)
select *
from cte
order by ParentID

查询结果如图:

4,由子级向父级的递归查询

;with cte as
(
select ID,ParentID,name
from dbo.hierarchy
where id= --芦集乡的ID union all
select h.ID,h.ParentID,h.name
from dbo.hierarchy h
inner join cte c on h.id=c.ParentID
)
select ID,ParentID,name
from cte
order by ParentID

查询结果如图:

参考文档:

Recursive Queries Using Common Table Expressions

WITH common_table_expression (Transact-SQL)

SQL Server CTE 递归查询全解 -- 转 学习的更多相关文章

  1. SQL Server CTE 递归查询全解

    在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询,本文详细介绍CTE递归调用的特性和使用示例 ...

  2. SQL Server CTE 递归查询全解(转载)

    在TSQL脚本中,也能实现递归查询,SQL Server提供CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询,本文详细介绍CTE递归调用的特性和使用示例 ...

  3. CTE 递归查询全解

    TSQL脚本能实现递归查询,用户使用共用表表达式 CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询.本文详细介绍CTE递归调用的特性和使用示例,递归查询 ...

  4. sql server实用要点全解

    本文介绍sql server的相关的查询语句和标准T-sql语法 写在前面 sqlsever使用注意点 可以运行 services.msc 打开服务窗口 自增列默认无法手动设置,使用 set iden ...

  5. SQL Server表分区详解

    原文:SQL Server表分区详解 什么是表分区 一般情况下,我们建立数据库表时,表数据都存放在一个文件里. 但是如果是分区表的话,表数据就会按照你指定的规则分放到不同的文件里,把一个大的数据文件拆 ...

  6. MS SQL Server 数据库连接字符串详解

    MS SQL Server 数据库连接字符串详解 原地址:http://blog.csdn.net/jhhja/article/details/6096565 问题 : 超时时间已到.在从池中获取连接 ...

  7. Win8.1下安装sql server 2008 r2详解

    我是来斗图的,安装了好多次,有一些配置还是不能烂熟于心啊,所以就想起来了米老师那句话,学习是个反复的过程.写个教程吧,很简单但是很实用. 首先打开"setup.exe"出现以下界面 ...

  8. SQL Server中的锁的简单学习

    简介 在SQL Server中,每一个查询都会找到最短路径实现自己的目标.如果数据库只接受一个连接一次只执行一个查询.那么查询当然是要多快好省的完成工作.但对于大多数数据库来说是需要同时处理多个查询的 ...

  9. JDBC连接SQL Server 2005步骤详解

    一.设置SQL Server服务器:    1.“开始” → “程序” → “Microsoft SQL Server 2005” → “配置工具” → “SQL Server Configurati ...

随机推荐

  1. Eclipse Debug不能热部署解决

    摘要: Eclipse Debug不能热部署代码may be out-of-synch 问题描述:Project通过ant工具编译部署到JBoss下,在使用Eclipse远程调试功...       ...

  2. (9/24) 图片跳坑大战--css分离与图片路径处理

    前言: 在上一节当中,我们把小图片打包成Base64格式(打包到了js当中).我们也算是对webpack对图片的打包有个基本了解. 本节我们准备把css从JavasScript代码中分离出来,这会遇到 ...

  3. leetcode84

    public class Solution { public int LargestRectangleArea(int[] hist) { // The main function to find t ...

  4. “AS3.0高级动画编程”学习:第四章 寻路(AStar/A星/A*)算法 (下)

    在前一部分的最后,我们给出了一个寻路的示例,在大多数情况下,运行还算良好,但是有一个小问题,如下图: 很明显,障碍物已经把路堵死了,但是小球仍然穿过对角线跑了出来! 问题在哪里:我们先回顾一下ASta ...

  5. mysql学习笔记--数据库单表查询

    一.查询语句 1.  select [选项] 列名 [from 表名]  [where 条件]  [order by 排序]  [group by 分组]  [having 条件]  [limit 限 ...

  6. cmd中sudo以后显示password不能输入密码

    文本界面还是图形界面下输入密码都不会有回显,这是为了安全考虑. 其实你不是不能输入密码只是你看不到而已,事实上你已经输入进去了,回车后就能看到效果了. 来源于:https://zhidao.baidu ...

  7. 【python中二叉树的实现】python中二叉树的创建、三种方式递归遍历和非递归遍历

    代码如下: # coding=utf-8 class myNode(object): def __init__(self, data=-1, lchild=None, rchild=None): se ...

  8. ExecuteNonQuery()

    ExecuteNonQuery():执行一个SQL语句,返回受影响的行数,这个方法主要用于执行对数据库执行增加.更新.删除操作,注意查询的时候不是调用这个方法.用于完成insert,delete,up ...

  9. Solidity类型Uint类型区分?

    1. Solidity中默认 Uint 也就是Uint256, 也就是 无符号 256位整数范围,即 2的 256次方 减一的 10进制范围, 预计大小为: 115792089237316195423 ...

  10. application/json和application/x-www-form-urlencoded使用选择

    一.参考资料 选application/x-www-form-urlencoded还是application/json? @RequestBody应用 二.理解 1.@RequestBody的作用 注 ...