递归查询(树查询)

  递归查询(树查询)在一般用于菜单/权限/分类等,在不同的数据库中有各自的查询方式. 本文介绍了在Oracle/sqlserver 两种数据库中树查询的语法结构.
  
1. Oracle 树查询 使用语法connect by (prior) t.parent_id = (prior) t.id start with id = ??
prior 只有一个,在不同的位置查不同的结果.prior 在前查前辈,prior在后查后生

示例1 查询已知节点所有的父(祖)节点(查询id = 140408 和其所有的父菜单)

select t.id,t.parent_id,t.value 
  from sys_resource t 
  where t.resource_type = 'menu' 
  connect by prior t.parent_id = t.id start with id =140408;

结果

这里写图片描述



示例2 查询一个节点所有的子(孙)节点(查询id = 14 和其所有的子菜单)

select t.id,t.parent_id,t.value 
       from sys_resource t 
       where t.resource_type = 'menu' 
       connect by  t.parent_id =  prior t.id start with t.id = 14 
       order by t.parent_id;

结果
这里写图片描述


注意查父节点和子节点区别 prior 位置不同.(记忆:prior 在前查前辈,prior在后查后生)

2. SQL SERVER 树查询 sqlserver 树查询相对麻烦一些需要使用到CTE(Common Table Expression公用表表达式)

示例3 查所有父(祖)节点

with CTE_SYS_RESOURCE(ID,RESOURCE_TYPE,VALUE,PARENT_ID)  
as  
(  
    --起始条件  
    select ID,RESOURCE_TYPE,VALUE ,PARENT_ID
    from dbo.SYS_RESOURCE  
    where id = 30023   --列出父节点查询条件  

    union all  
    --递归条件  

    select a.ID,a.RESOURCE_TYPE,a.VALUE,a.PARENT_ID 
    from SYS_RESOURCE a  
    inner join   
    CTE_SYS_RESOURCE b          --执行递归   
    on a.id=b.PARENT_ID 
) 
select * from CTE_SYS_RESOURCE t; 

结果
这里写图片描述

示例4 查所有子(孙)节点

with CTE_SYS_RESOURCE(ID,RESOURCE_TYPE,VALUE,PARENT_ID) 
as  
(  
    --起始条件  
    select ID,RESOURCE_TYPE,VALUE ,PARENT_ID
    from dbo.SYS_RESOURCE  
    where id = 30000   --列出子节点查询条件  

    union all  

    --递归条件  
    select a.ID,a.RESOURCE_TYPE,a.VALUE,a.PARENT_ID 
    from SYS_RESOURCE a  
    inner join   
    CTE_SYS_RESOURCE b          --执行递归
    on a.PARENT_ID=b.id 
)                         
select * from CTE_SYS_RESOURCE t;  

结果
这里写图片描述

Oracle/sqlserver对CTE都是支持的.但是二者有些细微的差别. 示例3/示例4中的sql在Oracle中也可以正确运行,但是在sqlserver中,示例3可以简化成如下sql (CTE_SYS_RESOURCE 列名省略了)

WITH CTE_SYS_RESOURCE AS 
(
    SELECT T.ID,T.PARENT_ID,T.RESOURCE_TYPE,T.VALUE FROM dbo.SYS_RESOURCE T WHERE T.ID = 30023
    UNION ALL
    SELECT T1.ID,T1.PARENT_ID,T1.RESOURCE_TYPE,T1.VALUE FROM dbo.SYS_RESOURCE T1,CTE_SYS_RESOURCE T2 WHERE T1.ID = T2.PARENT_ID
)
SELECT * FROM CTE_SYS_RESOURCE ;

在sqlserver中,递归CTE 可以把列名省略,但是递归CTE在Oracle中不能省略列名. 当然普通的CTE在sqlserver/Oracle中均可省略列名.

CTE 的介绍可以参考
CTE 说明1
CTE 说明2

Mysql 树查询暂未了解,后继补上.

/** * 根据等级查询类目 * * @param level * @return */ @Override public List queryCategoryTree(Integer level) { //查询当前级别下类目 List list = categoryDAO.list(level); //组装好的类目,返回前端 List categoryTree = new ArrayList(); //所有类目 List allDTOList = new ArrayList(); if (CollectionUtils.isEmpty(list)) { return categoryTree; } for (CategoryDO categoryDO : list) { allDTOList.add(new CategoryTreeDTO().convertDOToDTO(categoryDO)); } //当前等级类目 categoryTree = allDTOList.stream().filter(dto -> level.equals(dto.getLevel())).collect(Collectors.toList()); for (CategoryTreeDTO categoryTreeDTO : categoryTree) { //组装类目为结构 assembleTree(categoryTreeDTO, allDTOList,Constants.CATEGORY_MAX_LEVEL - level); } return categoryTree; } /** * 组装 * * @param categoryTreeDTO * @param allList * @param remainRecursionCount 剩余递归次数 * @return */ public CategoryTreeDTO assembleTree(CategoryTreeDTO categoryTreeDTO, List allList, int remainRecursionCount) { remainRecursionCount--; //最大递归次数不超过Constants.CATEGORY_MAX_LEVEL-level次,防止坏数据死循环 if(remainRecursionCount < 0){ return categoryTreeDTO; } String categoryCode = categoryTreeDTO.getCategoryCode(); Integer level = categoryTreeDTO.getLevel(); //到达最后等级返回 if (Constants.CATEGORY_MAX_LEVEL == level) { return categoryTreeDTO; } //子类目 List child = allList.stream().filter(a -> categoryCode.equals(a.getParentCode())).collect(Collectors.toList()); if (null == child) { return categoryTreeDTO; } categoryTreeDTO.setChildren(child); //组装子类目 for (CategoryTreeDTO dto : child) { assembleTree(dto, allList,remainRecursionCount); } return categoryTreeDTO; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值