SQL递归查询(SqlServer/ORACLE递归查询)[语法差异分析]

SQL递归查询(SqlServer/ORACLE递归查询)[语法差异分析]

在 SQLSERVER2005以后,mssql开始有了递归查询的方法了。比较起最开始写存储过程或者写function的方式。这样的方式更加简便灵活的。

而oracle也有自带的树形结构递归查询方法,connect by

下面我自己写的一段SQL,简单注释下CTE共用表达式的一些用法。 实现对树状结构的根节点和子节点的查询。

 


-- ----------------------------------------------------------------------
--
 author:jc_liumangtu(【DBA】小七)
--
 date:    2010-03-30 15:09:42
--
 version:
--
 Microsoft SQL Server 2005 - 9.00.1399.06 (Intel X86) 
--
     Oct 14 2005 00:33:37 
--
     Copyright (c) 1988-2005 Microsoft Corporation
--
     Developer Edition on Windows NT 5.1 (Build 2600: Service Pack 3)
--
 
--
----------------------------------------------------------------------
use  test
set  nocount  on
if   object_id ( ' Dept ' , ' U ' is   not   null
drop   table  Dept
go
create   table  Dept(ID  int ,ParentID  int ,Name  varchar ( 20 ))   
insert   into  Dept  select   1 , 0 , ' AA '  
insert   into  Dept  select   2 , 1 , ' BB '  
insert   into  Dept  select   3 , 1 , ' CC '   
insert   into  Dept  select   4 , 2 , ' DD '   
insert   into  Dept  select   5 , 3 , ' EE '   
insert   into  Dept  select   6 , 0 , ' FF '  
insert   into  Dept  select   7 , 6 , ' GG '  
insert   into  Dept  select   8 , 7 , ' HH '  
insert   into  Dept  select   9 , 7 , ' II '  
insert   into  Dept  select   10 , 7 , ' JJ '  
insert   into  Dept  select   11 , 9 , ' KK '  
 
go    
SELECT   *   FROM  Dept;

-- 查询树状结构某节点的上级所有根节点。
with  cte_root(ID,ParentID,NAME)
as
(
    
-- 起始条件
     select  ID,ParentID,NAME
    
from  Dept
    
where  Name  =   ' II '     -- 列出子节点查询条件
     union   all
    
-- 递归条件
     select  a.ID,a.ParentID,a.NAME
    
from  Dept a
    
inner   join  
    cte_root b          
-- 执行递归,这里就要理解下了 
     on  a.ID = b.ParentID   -- 根据基础表条件查询子节点(a.ID),通过CTE递归找到其父节点(b.ParentID)。
)                        -- 可以和下面查询子节点的cte_child对比。
select   *   from  cte_root ;

-- 查询树状结构某节点下的所有子节点。
with  cte_child(ID,ParentID,NAME)
as
(
    
-- 起始条件
     select  ID,ParentID,NAME
    
from  Dept
    
where  Name  =   ' II '   -- 列出父节点查询条件
     union   all
    
-- 递归条件
     select  a.ID,a.ParentID,a.NAME
    
from  Dept a
    
inner   join  
    cte_child b
    
on  ( a.ParentID = b.ID)   -- 根据查询到的父节点(a.Parent),通过CTE递归查询出其子节点(b.ID)
)

select   *   from  cte_child  -- 可以改变之前的查询条件'II'再测试结果


ID          ParentID    Name
-- --------- ----------- --------------------
1             0            AA
2             1            BB
3             1            CC
4             2            DD
5             3            EE
6             0            FF
7             6            GG
8             7            HH
9             7            II
10            7            JJ
11            9            KK

ID          ParentID    NAME
-- --------- ----------- --------------------
9             7            II
7             6            GG
6             0            FF

ID          ParentID    NAME
-- --------- ----------- --------------------
9             7            II
11            9            KK

 

 在msdn中介绍了CTE的一些限制:

至少有一个定位点成员和一个递归成员,当然,你可以定义多个定位点成员和递归成员,但所有定位点成员必须在递归成员的前面 
定位点成员之间必须使用UNION ALL、UNION、INTERSECT、EXCEPT集合运算符,最后一个定位点成员与递归成员之间必须使用UNION ALL,递归成员之间也必须使用UNION ALL连接 
定位点成员和递归成员中的字段数量和类型必须完全一致 
递归成员的FROM子句只能引用一次CTE对象 
递归成员中不允许出现下列项 
    SELECT DISTINCT 
    GROUP BY 
    HAVING 
    标量聚合 
    TOP 
    LEFT、RIGHT、OUTER JOIN(允许出现 INNER JOIN) 
    子查询

 接下来介绍下Oracle里面的递归查询方法,connect by prior ,start with。相对于SqlServer来说,Oracle的方法更加简洁明了,简单易懂。很容易就让人理解其用法。借来我会用和上面SqlServer同样的数据和结构进行代码演示,和对一些关键字的用法进行阐述。

 

SELECT …..

CONNECT BY {PRIOR 列名1=列名2|列名1=PRIOR 列名2}
[START WITH];

下面是代码测试:

 



-- 创建表
create   table  Dept(ID  int ,ParentID  int ,Name  varchar ( 20 ));
-- 增加测试数据,和上面的SqlServer数据相同
insert   into  Dept   select   1 , 0 , ' AA '   from  dual;
insert   into  Dept   select   2 , 1 , ' BB '   from  dual;
insert   into  Dept   select   3 , 1 , ' CC '    from  dual;
insert   into  Dept   select   4 , 2 , ' DD '    from  dual;
insert   into  Dept   select   5 , 3 , ' EE '    from  dual;
insert   into  Dept   select   6 , 0 , ' FF '   from  dual;
insert   into  Dept   select   7 , 6 , ' GG '   from  dual;
insert   into  Dept   select   8 , 7 , ' HH '   from  dual;
insert   into  Dept   select   9 , 7 , ' II '   from  dual;
insert   into  Dept   select   10 , 7 , ' JJ '   from  dual;
insert   into  Dept   select   11 , 9 , ' KK '   from  dual;
commit ;

-- 查询根节点(父节点)
select   *   from  Dept             -- 查询基础表
connect  by  id = prior parentid   -- connect by就是字段的关联关键字,prior有预先和前的意思,则是放在哪个字段前,哪个就是递归的上一层
start  with  name = ' II ' ;          -- start with则是递归的起始位置,也可以用id或者是parentid。可以修改II的值测试其他数据。

-- 查询结果
ID    PARENTID    NAME
9        7             II
7        6             GG
6        0             FF

-- 查询子节点

select   *   from  Dept 
connect 
by  prior id = parentid   -- 同样的语句,仅仅改变prior位子,就发生了指向性的变化,就是这里id为递归上一层。
start  with  name = ' II ' ;

-- 查询结果
ID    PARENTID    NAME
9         7             II
11      9             KK

-- 测试结果和SqlServer一致,语句却更精练,简洁易懂。


 

 

经过分别对SqlServer和Oracle的测试,发现两个数据库都很好的支持递归查询,相比之下Oracle的递归查询语句更加简练易懂,更容易让人理解。

在做测试的时候,SqlServer更方便的产生测试数据,上面的代码可以复制后重复执行,而Oracle复制执行一次可以,重复执行的话,在执行创建表的工作,就会报错了,原因很简单,Oracle要判断表存在然后删除后重建的工作用代码实现很麻烦。而SqlServer只需要if后drop表再create就搞定。所以两种数据库各有千秋。

你可能感兴趣的:(数据库,sqlServer,oracle)