`
wgq837051
  • 浏览: 86043 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

oracle树查询(转)

阅读更多
Oracle树查询的最重要的就是select...start with... connect by ...prior 语法了。依托于该语法,我们可以将一个表形结构的中以树的顺序列出来。在下面列述了Oracle中树型查询的常用查询方式以及经常使用的与树查询相关的Oracle特性函数等,在这里只涉及到一张表中的树查询方式而不涉及多表中的关联等。

      以我做过的一个项目中的表为例,表结构如下:

Sql代码 
CREATE TABLE FLFL  
(  
  ID      NUMBER                                NOT NULL,  
  MC      NVARCHAR2(20),  
  FLJB    NUMBER,  
  SJFLID  NUMBER  


CREATE TABLE FLFL
(
  ID      NUMBER                                NOT NULL,
  MC      NVARCHAR2(20),
  FLJB    NUMBER,
  SJFLID  NUMBER
)      FLJB是作为树的级别,在很多查询中可以加快SQL的查询效率。在下面演示的功能基本上不使用这个关键字。

      SJFLID存储的是上级ID,如果是顶级父节点,该SJFLID为null(得补充一句,当初的确是这样设计的,不过现在知道,表中最好别有null记录,这会引起全文扫描,建议改成0代替)。

      我们从最基本的操作,逐步列出树查询中常见的操作,所以查询出来的节点以家族中的辈份作比方。



      1. 查找树中的所有顶级父节点(辈份最长的人)。 假设这个树是个目录结构,那么第一个操作总是找出所有的顶级节点,再根据该节点找到其下属节点。

Sql代码 
SELECT * FROM flfl WHERE sjflid IS NULL; 

SELECT * FROM flfl WHERE sjflid IS NULL;      这是个引子,没用到树型查询。



      2.查找一个节点的直属子节点(所有儿子)。 如果查找的是直属子类节点,也是不用用到树型查询的。

Sql代码 
SELECT * FROM flfl WHERE sjflid = 819459; 

SELECT * FROM flfl WHERE sjflid = 819459;      这个可以找到ID为819459的直属子类节点。



      3.查找一个节点的所有 直属子节点(所有后代)。

Sql代码 
SELECT * FROM flfl START WITH ID = 819459 CONNECT BY sjflid = PRIOR ID; 

SELECT * FROM flfl START WITH ID = 819459 CONNECT BY sjflid = PRIOR ID;      这个查找的是ID为819459的节点下的所有直属子类节点,包括子辈的和孙子辈的所有直属节点。



      4.查找一个节点的直属父节点(父亲)。 如果查找的是节点的直属父节点,也是不用用到树型查询的。

Sql代码 
SELECT b.* FROM flfl a JOIN flfl b ON a.sjflid = b.ID WHERE a.ID = 6758; 

SELECT b.* FROM flfl a JOIN flfl b ON a.sjflid = b.ID WHERE a.ID = 6758;      这个找到的是ID为6758的节点的直属父节点,要用到同一张表的关联了。



      5.查找一个节点的所有直属父节点(祖宗)。

Sql代码 
SELECT * FROM flfl START WITH ID = 6758 CONNECT BY PRIOR sjflid = ID; 

SELECT * FROM flfl START WITH ID = 6758 CONNECT BY PRIOR sjflid = ID;      这里查找的就是ID为6758的所有直属父节点,打个比方就是找到一个人的父亲、祖父等。但是值得注意的是这个查询出来的结果的顺序是先列出子类节点再列出父类节点,姑且认为是个倒序吧。



      上面列出两个树型查询方式,第3条语句和第5条语句,这两条语句之间的区别在于prior关键字的位置不同,所以决定了查询的方式不同。 当sjflid = PRIOR ID时,数据库会根据当前的ID迭代出sjflid与该ID相同的记录,所以查询的结果是迭代出了所有的子类记录;而PRIOR ID = sjflid时,数据库会跟据当前的sjflid来迭代出与当前的sjflid相同的id的记录,所以查询出来的结果就是所有的父类结果。

      以下是一系列针对树结构的更深层次的查询,这里的查询不一定是最优的查询方式,或许只是其中的一种实现而已。



      6.查询一个节点的兄弟节点(亲兄弟)。

Sql代码 
SELECT a.*  
  FROM flfl a  
WHERE EXISTS (SELECT *  
                 FROM flfl b  
                WHERE a.sjflid = b.sjflid AND b.ID = 6757); 

SELECT a.*
  FROM flfl a
WHERE EXISTS (SELECT *
                 FROM flfl b
                WHERE a.sjflid = b.sjflid AND b.ID = 6757);      这里查询的就是与ID为6757的节点同属一个父节点的节点了,就好比亲兄弟了。



      7.查询与一个节点同级的节点(族兄弟)。 如果在表中设置了级别的字段,上表中的FLJB,那么在做这类查询时会很轻松,同一级别的就是与那个节点同级的,在这里列出不使用该字段时的实现!

Sql代码 
WITH tmp AS 
     (SELECT     a.*, LEVEL lev  
            FROM flfl a  
      START WITH a.sjflid IS NULL 
      CONNECT BY a.sjflid = PRIOR a.ID)  
SELECT *  
  FROM tmp  
WHERE lev = (SELECT lev  
                FROM tmp  
               WHERE ID = 819394) 

WITH tmp AS
     (SELECT     a.*, LEVEL lev
            FROM flfl a
      START WITH a.sjflid IS NULL
      CONNECT BY a.sjflid = PRIOR a.ID)
SELECT *
  FROM tmp
WHERE lev = (SELECT lev
                FROM tmp
               WHERE ID = 819394)       这里使用两个技巧,一个是使用了LEVEL来标识每个节点在表中的级别,还有就是使用with语法模拟出了一张带有级别的临时表。



      8.查询一个节点的父节点的的兄弟节点(伯父与叔父)。

Sql代码 
WITH tmp AS 
     (SELECT     flfl.*, LEVEL lev  
            FROM flfl  
      START WITH sjflid IS NULL 
      CONNECT BY sjflid = PRIOR ID)  
SELECT b.*  
  FROM tmp b,  
       (SELECT *  
          FROM tmp  
         WHERE ID = 7004 AND lev = 2) a  
WHERE b.lev = 1  
UNION ALL 
SELECT *  
  FROM tmp  
WHERE sjflid = (SELECT DISTINCT x.ID  
                            FROM tmp x,  
                                 tmp y,  
                                 (SELECT *  
                                    FROM tmp  
                                   WHERE ID = 7004 AND lev > 2) z  
                           WHERE y.ID = z.sjflid AND x.ID = y.sjflid); 

WITH tmp AS
     (SELECT     flfl.*, LEVEL lev
            FROM flfl
      START WITH sjflid IS NULL
      CONNECT BY sjflid = PRIOR ID)
SELECT b.*
  FROM tmp b,
       (SELECT *
          FROM tmp
         WHERE ID = 7004 AND lev = 2) a
WHERE b.lev = 1
UNION ALL
SELECT *
  FROM tmp
WHERE sjflid = (SELECT DISTINCT x.ID
                            FROM tmp x,
                                 tmp y,
                                 (SELECT *
                                    FROM tmp
                                   WHERE ID = 7004 AND lev > 2) z
                           WHERE y.ID = z.sjflid AND x.ID = y.sjflid);       这里查询分成以下几步。首先,将第7个一样,将全表都使用临时表加上级别;其次,根据级别来判断有几种类型,以上文中举的例子来说,有三种情况:(1)当前节点为顶级节点,即查询出来的lev值为1,那么它没有上级节点,不予考虑。(2)当前节点为2级节点,查询出来的lev值为2,那么就只要保证lev级别为1的就是其上级节点的兄弟节点。(3)其它情况就是3以及以上级别,那么就要选查询出来其上级的上级节点(祖父),再来判断祖父的下级节点都是属于该节点的上级节点的兄弟节点。 最后,就是使用UNION将查询出来的结果进行结合起来,形成结果集。



      9.查询一个节点的父节点的同级节点(族叔)。

      这个其实跟第7种情况是相同的。

Sql代码 
WITH tmp AS 
     (SELECT     a.*, LEVEL lev  
            FROM flfl a  
      START WITH a.sjflid IS NULL 
      CONNECT BY a.sjflid = PRIOR a.ID)  
SELECT *  
  FROM tmp  
WHERE lev = (SELECT lev  
                FROM tmp  
               WHERE ID = 819394) - 1 

WITH tmp AS
     (SELECT     a.*, LEVEL lev
            FROM flfl a
      START WITH a.sjflid IS NULL
      CONNECT BY a.sjflid = PRIOR a.ID)
SELECT *
  FROM tmp
WHERE lev = (SELECT lev
                FROM tmp
               WHERE ID = 819394) - 1      只需要做个级别判断就成了。



      基本上,常见的查询在里面了,不常见的也有部分了。其中,查询的内容都是节点的基本信息,都是数据表中的基本字段,但是在树查询中还有些特殊需求,是对查询数据进行了处理的,常见的包括列出树路径等。

      补充一个概念,对于数据库来说,根节点并不一定是在数据库中设计的顶级节点,对于数据库来说,根节点就是start with开始的地方。

      下面列出的是一些与树相关的特殊需求。



      10.名称要列出名称全部路径。

      这里常见的有两种情况,一种是是从顶级列出,直到当前节点的名称(或者其它属性);一种是从当前节点列出,直到顶级节点的名称(或其它属性)。举地址为例:国内的习惯是从省开始、到市、到县、到居委会的,而国外的习惯正好相反(老师说的,还没接过国外的邮件,谁能寄个瞅瞅 )。

      从顶部开始:

Sql代码 
SELECT     SYS_CONNECT_BY_PATH (mc, '/')  
      FROM flfl  
     WHERE ID = 6498  
START WITH sjflid IS NULL 
CONNECT BY sjflid = PRIOR ID; 

SELECT     SYS_CONNECT_BY_PATH (mc, '/')
      FROM flfl
     WHERE ID = 6498
START WITH sjflid IS NULL
CONNECT BY sjflid = PRIOR ID;      从当前节点开始:

Sql代码 
SELECT     SYS_CONNECT_BY_PATH (mc, '/')  
      FROM flfl  
START WITH ID = 6498  
CONNECT BY PRIOR sjflid = ID; 

SELECT     SYS_CONNECT_BY_PATH (mc, '/')
      FROM flfl
START WITH ID = 6498
CONNECT BY PRIOR sjflid = ID;      在这里我又不得不放个牢骚了。oracle只提供了一个sys_connect_by_path函数,却忘了字符串的连接的顺序。在上面的例子中,第一个SQL是从根节点开始遍历,而第二个SQL是直接找到当前节点,从效率上来说已经是千差万别,更关键的是第一个SQL只能选择一个节点,而第二个SQL却是遍历出了一颗树来。再次PS一下。

      sys_connect_by_path函数就是从start with开始的地方开始遍历,并记下其遍历到的节点,start with开始的地方被视为根节点,将遍历到的路径根据函数中的分隔符,组成一个新的字符串,这个功能还是很强大的。



      11.列出当前节点的根节点。

      在前面说过,根节点就是start with开始的地方。

Sql代码 
SELECT     CONNECT_BY_ROOT mc, flfl.*  
      FROM flfl  
START WITH ID = 6498  
CONNECT BY PRIOR sjflid = ID; 

SELECT     CONNECT_BY_ROOT mc, flfl.*
      FROM flfl
START WITH ID = 6498
CONNECT BY PRIOR sjflid = ID;      connect_by_root函数用来列的前面,记录的是当前节点的根节点的内容。



      12.列出当前节点是否为叶子。

      这个比较常见,尤其在动态目录中,在查出的内容是否还有下级节点时,这个函数是很适用的。

Sql代码 
SELECT     CONNECT_BY_ISLEAF, flfl.*  
      FROM flfl  
START WITH sjflid IS NULL 
CONNECT BY sjflid = PRIOR ID; 

SELECT     CONNECT_BY_ISLEAF, flfl.*
      FROM flfl
START WITH sjflid IS NULL
CONNECT BY sjflid = PRIOR ID;      connect_by_isleaf函数用来判断当前节点是否包含下级节点,如果包含的话,说明不是叶子节点,这里返回0;反之,如果不包含下级节点,这里返回1。



     
分享到:
评论

相关推荐

    oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 连接字符串

    1. 层次结构模型: 层次结构模型实质上是一种有根结点的定向有序树,IMS(Information Manage-mentSystem)是其典型代表。 2. 网状结构模型:按照网状数据结构建立的数据库系统称为网状数据库系统,其典型代表是DBTG...

    Oracle SQL高级编程(资深Oracle专家力作,OakTable团队推荐)--随书源代码

    他认为对于SQL的学习是永无止境的,相信每一个查询Oracle数据库的人都需要精通SQL语言,才能写出高效的查询。他参与本书的编写就是为了帮助别人实现这一目标。 目录 封面 -11 封底 -10 扉页 -9 版权 -8 版权声明 -7...

    Oracle_Database_11g完全参考手册.part3/3

    《Oracle Database 11g完全参考手册》全面详细地介绍了Oracle Database 11g的强大功能,阐述了如何使用所有的新增功能和工具,如何执行功能强大的SOL查询,如何编写PL/SQL和SQL*Plus语句,如何使用大对象和对象,...

    Oracle_Database_11g完全参考手册.part2/3

    《Oracle Database 11g完全参考手册》全面详细地介绍了Oracle Database 11g的强大功能,阐述了如何使用所有的新增功能和工具,如何执行功能强大的SOL查询,如何编写PL/SQL和SQL*Plus语句,如何使用大对象和对象,...

    Oracle自学(学习)材料 (共18章 偏理论一点)

    12 管理索引 目标 12-2 索引的分类 12-3 B 树索引 12-4 位图索引 12-6 B 树索引和位图索引的比较 12-7 创建普通 B 树索引 12-8 创建索引:指导 12-10 创建位图索引 12-11 修改索引的储存参数 12-12 分配和回收索引...

    Oracle Database 11g初学者指南--详细书签版

    3.5.2 目录信息树 60 3.5.3 标识名 61 3.5.4 如何查找目录命名信息 61 3.5.5 网络服务别名条目 61 3.5.6 本地命名方法 62 3.5.7 简单命名方法 62 3.5.8 外部命名方法 62 3.5.9 使用哪种命名方法 62 3.6 ...

    Oracle8i_9i数据库基础

    §7.3 家族树 184 §7.3.1 排除单一体和分枝 184 §7.3.2 遍历至根 185 §7.4 在from 中使用视图 187 第八章 一些高级的用法 188 §8.1 关于DECODE 188 §8.1.1 DECODE 中的if-then-else逻辑 188 §8.1.2 DECODE 的...

    精通SQL 结构化查询语言详解

    10.6 树查询 第11章 数据插入操作  11.1 插入单行记录  11.1.1 基本语法  11.1.2 整行插入  11.1.3 NULL值的插入 11.1.4 惟一值的插入  11.1.5 特定字段数据插入  11.1.6 通过视图插入行 11.2 插入...

    oracle学习经典教程

    1.2.2.1 B 树索引 (默认类型) ...........................32 1.2.2.2 位图索引.................33 1.2.2.3 HASH 索引................35 1.2.2.4 索引组织表.............36 1.2.2.5 反转键索引........

    Oracle 10g 开发与管理

    本文是由笔者2012年学习oracle数据库时编写的学习札记,其中的题目 多数为老师留下的思考题目。 我相信本文会对初学者使用oracle有一个初步的使用印象。右图为我所参 考的书籍。 目录 第一讲 Oacle关系数据库 ...

    JSP+Servlet+EJB3.0+Oracle10g火车售票系统

    本系统主要实现火车查询售票功能,主要的功能如下: 客户端管理功能: (1)动车基本信息管理模块;(2)车次查询模块,两站之间的车次查询,某车站中转站所有的车次的查询,具体某车次的查询;(3)售票模块,车票的预定; (4)...

    ORACLE检查找出损坏索引(Corrupt Indexes)的方法详解

    索引一旦被建立就将被Oracle系统自动维护,查询语句中不用指定使用哪个索引. 从物理上说,索引通常可以分为:分区和非分区索引、常规B树索引、位图(bitmap)索引、翻转(reverse)索引等。其中,B树索引属于最常见...

    Oracle事例

    24、树形查询 create table zj( bm number(8), bmmc varchar2(20), sjbm number(8) ) insert into zj values(1,\'aaa\',0) insert into zj values(11,\'aaa1\',1) insert into zj values(12,\'aaa2\',1) ...

    TianleSoftware Oracle中文学习手册

    1.2.1.7 查询索引........................................................................................................ 1.2.1.8 组合索引..................................................................

    (E文)基于成本的Oracle优化法则.pdf

    7.2.2 Oracle何时忽略直方图 149 7.3 频率直方图 152 7.3.1 伪造频率直方图 155 7.3.2 注意事项 156 7.4 “高度均衡”直方图 157 7.5 重新审视数据问题 163 7.5.1 愚蠢的数据类型 163 7.5.2 危险的默认值 166 7.6 本...

    Navicat Premium操作手册.7z

    5SQL Server 分区函数146SQL Server 分区方案147SQL 预览147维护147维护...Oracle 查询(只限于完整版本)173模型(只限于Navicat Premium 和企业版)174边栏面板174模型树窗格174图表树窗格175属性窗格175历史窗格177...

    精通SQL--结构化查询语言详解

    10.6 树查询 205 第11章 数据插入操作 209 11.1 插入单行记录 209 11.1.1 基本语法 209 11.1.2 整行插入 209 11.1.3 null值的插入 211 11.1.4 惟一值的插入 212 11.1.5 特定字段数据插入 213 11.1.6 通过...

Global site tag (gtag.js) - Google Analytics