SQL递归查询(SqlServer/ORACLE递归查询)[语法差异分析]
发布日期:2021-09-08 01:44:46 浏览次数:32 分类:技术文章

本文共 4102 字,大约阅读时间需要 13 分钟。

在 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就搞定。所以两种数据库各有千秋。

转载地址:https://blog.csdn.net/weixin_34310369/article/details/85557421 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Python extensions(转)
下一篇:逻辑地址和物理地址

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月01日 09时19分48秒