sql 树状查询

;with cte as

(

select from tb where [email protected]

union all

select a.* from tb a join cte b on a.id=b.pid

)

select from cte

http://bbs.csdn.net/topics/380180222

公用表表达式(Common Table Expression)是SQL SERVER 2005版本之后引入的一个特性.CTE可以看作是一个临时的结果集,可以在接下来的一个SELECT,INSERT,UPDATE,DELETE,MERGE语句中被多次引用。使用公用表达式可以让语句更加清晰简练.

除此之外,根据微软对CTE好处的描述,可以归结为四点:

  • 可以定义递归公用表表达式(CTE)
  • 当不需要将结果集作为视图被多个地方引用时,CTE可以使其更加简洁
  • GROUP BY语句可以直接作用于子查询所得的标量列
  • 可以在一个语句中多次引用公用表表达式(CTE)

公用表表达式(CTE)的定义



公用表达式的定义非常简单,只包含三部分:

  1. 公用表表达式的名字(在WITH之后)
  2. 所涉及的列名(可选)
  3. 一个SELECT语句(紧跟AS之后)

在MSDN中的原型:

WITH expression_name [ ( column_name [,...n] ) ] 

AS 

( CTE_query_definition ) 

按照是否递归,可以将公用表(CTE)表达式分为递归公用表表达式和非递归公用表表达式.

非递归公用表表达式(CTE)



非递归公用表表达式(CTE)是查询结果仅仅一次性返回一个结果集用于外部查询调用。并不在其定义的语句中调用其自身的CTE

非递归公用表表达式(CTE)的使用方式和视图以及子查询一致

比如一个简单的非递归公用表表达式:

当然,公用表表达式的好处之一是可以在接下来一条语句中多次引用:

前面我一直强调“在接下来的一条语句中”,意味着只能接下来一条使用:

由于CTE只能在接下来一条语句中使用,因此,当需要接下来的一条语句中引用多个CTE时,可以定义多个,中间用逗号分隔:

递归公用表表达式(CTE)



递归公用表表达式很像派生表(Derived Tables ),指的是在CTE内的语句中调用其自身的CTE.与派生表不同的是,CTE可以在一次定义多次进行派生递归.对于递归的概念,是指一个函数或是过程直接或者间接的调用其自身,递归的简单概念图如下:

递归在C语言中实现的一个典型例子是斐波那契数列:

long fib(int n)   
{  
     if (n==0) return 0;
   if (n==1) return 1;   
     if (n>1) return fib(n-1)+fib(n-2);
} 

上面C语言代码可以看到,要构成递归函数,需要两部分。第一部分是基础部分,返回固定值,也就是告诉程序何时开始递归。第二部分是循环部分,是函数或过程直接或者间接调用自身进行递归.

对于递归公用表达式来说,实现原理也是相同的,同样需要在语句中定义两部分:

  • 基本语句
  • 递归语句

在SQL这两部分通过UNION ALL连接结果集进行返回:

比如:在AdventureWork中,我想知道每个员工所处的层级,0是最高级

这么复杂的查询通过递归CTE变得如此优雅和简洁.这也是CTE最强大的地方.

当然,越强大的力量,就需要被约束.如果使用不当的话,递归CTE可能会出现无限递归。从而大量消耗SQL Server的服务器资源.因此,SQL Server提供了OPTION选项,可以设定最大的递归次数:

还是上面那个语句,限制了递归次数:

所提示的消息:

这个最大递归次数往往是根据数据所代表的具体业务相关的,比如这里,假设公司层级最多只有2层.

总结



CTE是一种十分优雅的存在。CTE所带来最大的好处是代码可读性的提升,这是良好代码的必须品质之一。使用递归CTE可以更加轻松愉快的用优雅简洁的方式实现复杂的查询。

 

时间: 2024-12-13 14:20:09

sql 树状查询的相关文章

oracle中的树状查询

oracle中的树状查询 工作中经常会遇到将数据库中的数据以树的形式展现的需求.以下我们来看一下该需求在Oracle中如何实现. 首先我们需要有一个树形的表结构(当然有时候会出现表结构不是典型的树形结构,而是多表存储,需要根据多表连接查询生成树) 一.树型表结构:节点ID  上级ID  节点名称 二.用法: select 节点ID,节点名称,levelfrom 表名connect by prior 节点ID=上级节点IDstart with 上级节点ID=节点值 说明:1.常见的树形结构为公司组

SQL Server 父子迭代查询语句,树状查询(转)

-- Get childs by parent id WITH Tree AS ( SELECT Id,ParentId FROM dbo.Node P WHERE P.Id = 21 -- parent id UNION ALL SELECT C.Id,C.ParentId FROM dbo.Node C INNER JOIN Tree T ON C.ParentId = T.Id ) SELECT * FROM Tree -- Get parents by child id WITH Tre

在SqlServer中通过SQL语句实现树状查询

1 CREATE PROCEDURE [dbo].[GetTree] 2 @Id int 3 AS 4 BEGIN 5 with cte as 6 ( 7 select Id,Pid,Name,0 as lvl from Entity 8 where Id = @Id 9 union all 10 select e.Id,e.Pid,e.Name,lvl+1 from cte c inner join Entity e 11 on c.Id = e.Pid 12 ) 13 select * fr

SQL语句中使用 with 递归实现表中数据树状显示

在开发过程中会遇到很多实现树状的功能,之前为了实现数据的树状显示一般都是通过程序里面的递归实现,今天试了一下通过sql语句实现具体如下: 表名:DeptInfo 字段:DeptId(部门编号),DeptName(部门名称),DeptUpId(部门上级ID),DeptPath(部门层级) 从DeptUpId和DeptPath中可看出表数据可能很乱: 为了实现表中数据树状显示,条例清晰具体代码实现如下: with dept as(select DeptId,DeptUpId from DeptInf

3110: [Zjoi2013]K大数查询 树状数组套线段树

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1384  Solved: 629[Submit][Status] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a b c或2 a b

树状数组的区间修改与单点查询与区间查询

如何将普通树状数组升级 普通的单点修改单点查询就不讲了,从区间修改和单点查询讲起. 原来的值存在a[]里面,多建立个数组c1[],注意:c1[i]=a[i]-a[i-1]. 那么求a[i]的值的时候a[i]=a[i-1]+c1[i]=a[i-2]+c1[i]+c1[i-1]=-..=c1[1]+c1[2]+-+c1[i]. 所以就用c1[]建立树状数组,便可以很快查询a[i]的值.不多说,见代码. #include<iostream> #include<cstdio> #defin

【学习整理】树状数组 区间修改+查询

前言:对于区间修改和区间查询这样的简单问题,打一大堆线段树确实是不划算,所以学习了区间修改+区间修查询的树状数组. 我们定义 为原数列, ,显然  . 若想要将区间 的数全部 则只需要将 , 即可. 所以,我们维护一个数组 在将区间 的数全部 则还需同时将 , . 结论: 例题:CODEVS1082 线段树练习3 http://codevs.cn/problem/1082/ #include<iostream> #include<cstdio> #include<cstdli

HDU 3333 Turing Tree 树状数组 离线查询

题意: 给你一个数列,然后有n个查询,问你给定区间中不同数字的和是多少. 思路还是比较难想的,起码对于蒟蒻我来说. 将区间按照先右端点,后左端点从小到大排序之后,对于每个查询,我只要维护每个数字出现的最后一次就可以了(这个结论稍微想一下就可以证明是正确的). 然后就是简单的点更新,区间求和问题了- #include <cstdio> #include <cstring> #include <iostream> #include <map> #include

POJ2155 Matrix 【二维树状数组】+【段更新点查询】

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 17766   Accepted: 6674 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1