欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  数据库

Oracle树查询及相关函数

程序员文章站 2022-04-10 10:25:47
...

欢迎进入Oracle社区论坛,与200万技术人员互动交流 >>进入 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

欢迎进入Oracle社区论坛,与200万技术人员互动交流 >>进入

  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);

  这里查询分成以下几步。首先,将第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

  只需要做个级别判断就成了。

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

  补充一个概念,对于数据库来说,根节点并不一定是在数据库中设计的*节点,对于数据库来说,根节点就是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;

  从当前节点开始:

  Sql代码

  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;

  connect_by_root函数用来列的前面,记录的是当前节点的根节点的内容。

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

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

  Sql代码

  SELECT CONNECT_BY_ISLEAF, flfl.*

  FROM flfl

  START WITH sjflid IS NULL

  CONNECT BY sjflid = PRIOR ID;

  connect_by_isleaf函数用来判断当前节点是否包含下级节点,如果包含的话,说明不是叶子节点,这里返回0;反之,如果不包含下级节点,这里返回1。

  至此,oracle树型查询基本上讲完了,以上的例子中的数据是使用到做过的项目中的数据,因为里面的内容可能不好理解,所以就全部用一些新的例子来进行阐述。以上所有SQL都在本机上测试通过,也都能实现相应的功能,但是并不能保证是解决这类问题的最优方案(如第8条明显写成存储过程会更好),如果谁有更好的解决方案、或者有关oracle树查询的任何问题,欢迎留言讨论,以上的SQL有什么问题也欢迎大家留言批评。

[1] [2]

Oracle树查询及相关函数