SQL Cookbook 系列 - 分层查询

本文详细介绍了如何使用SQL进行分层查询,包括表示父-子、子-父-祖关系,创建分层视图,查找给定父行的所有子行,以及判断行是叶节点、分支节点还是根节点。示例覆盖了不同数据库系统如DB2、Oracle、SQL Server、MySQL和PostgreSQL的语法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 表示父-子关系
  2. 表示子-父-祖关系
  3. 创建表的分层视图
  4. 为给定父行找到所有的子行
  5. 确定哪些行是叶节点、分支节点及根节点

 

1.表示父-子关系

db2/oracle/postgresql:

select a.ename || ' works for ' || b.ename as info

from emp a,emp b where a.leaderno=b.empno;

mysql:

select concat(a.ename, ' works for ', b.ename) as info

from emp a,emp b where a.leaderno=b.empno;

sqlserver:

select a.ename + ' works for ' + b.ename as info

from emp a,emp b where a.leaderno=b.empno;

Note:最简答的单表自连接

 

2.表示子-父-祖关系

db2/sqlserver:

with x (tree,mgr,depth) as (

select cast(ename as varchar(100)),mgr,0

from emp where ename='Will'

union all

select cast(x.tree+'-->'+e.ename as varchar(100)),e.mgr,x.depth+1

from emp e,x where x.mgr=e.empno

)

select tree leaf_branch_root from x where depth=2;

oracle:

select ltrim(sys_connect_by_path(ename,'-->'),'-->') leaf_branch_root

from emp where level=3

start with ename='Will' connect by prior mgr=empno;

mysql/postgresql:

select a.ename||'-->'||b.ename||'-->'||c.ename as leaf_branch_root

from emp a,emp b, emp c

where a.ename='Will' and a.mgr=b.empno and b.mgr=c.empno;

Note:单表的多级连接

 

3.创建表的分层视图

db2/sqlserver:

with x (ename,empno) as (

select cast(ename as varchar(100)),empno

from emp where mgr is null

union all

select cast(x.ename||' - '||e.ename as varchar(100)),e.empno

from emp e,x where e.mgr=x.empno

)

select ename as emp_tree from x order by 1;

oracle:

select ltrim(sys_connenct_by_path(ename,' - '),' - ') emp_tree

from emp

start with mgr is null connect by prior empno=mgr order by 1;

postgresql:

select emp_tree from (

select ename as emp_tree

from emp where mgr is null

union

select a.ename||' - '||b.ename

from emp a join emp b on (a.empno=b.mgr)

where a.mgr is null

union

select rtrim(a.ename||' - '||b.ename||' - '||c.ename,' - ')

from emp a join emp b on (a.empno=b.mgr)

left join emp c on (b.empno=c.mgr)

where a.ename='Root'

union

select rtrim(a.ename||' - '||b.ename||' - '||c.ename||' - '||d.ename,' - ')

from emp a join emp b on (a.empno=b.mgr)

join emp c on (b.empno=c.mgr)

left join emp d on (c.empno=d.mgr)

where a.ename='Root'

) x where tree is not null order by 1;

mysql:

select emp_tree from (

select ename as emp_tree

from emp where mgr is null

union

select concat(a.ename,' - ',b.ename)

from emp a join emp b on (a.empno=b.mgr)

where a.mgr is null

union

select concat(a.ename,' - ',b.ename,' - ',c.ename)

from emp a join emp b on (a.empno=b.mgr)

left join emp c on (b.empno=c.mgr)

where a.ename='Root'

union

select concat(a.ename,' - ',b.ename,' - ',c.ename,' - ',d.ename)

from emp a join emp b on (a.empno=b.mgr)

join emp c on (b.empno=c.mgr)

left join emp d on (c.empno=d.mgr)

where a.ename='Root'

) x where tree is not null order by 1;

Note:因为层数不确定,在mysql和postgresql中操作很麻烦。

 

4.为给定父行找到所有的子行

db2/sqlserver:

with x(ename,empno) as (

select ename,empno from emp where ename='Will'

union all

select e.ename,e.empno from emp e,x where x.empno=e.mgr

)

select ename from x;

oracle:

select ename from emp start with ename='Will'

connect by prior empno=mgr;

mysql/postgresql:

多个查询连接之后在回找

Note:如果不能像oracle,自动进行关联,那么关系之中的关键关系值就显得非常重要

 

5.确定哪些行是叶节点、分支节点及根节点

db2/mysql/postgresql/sqlserver:

select e.ename,

(select sign(count(*)) from emp d

where 0=(select count(*) from emp f

where f.mgr=e.empno)) as is_leaf,

(select sign(count(*)) from emp d

where d.mgr=e.empno and e.mgr is not null) as is_branch,

(select sign(count(*)) from emp d

where d.empno=e.empno and d.mgr is null) as is_root

from emp e;

oracle:

select ename,connect_by_isleaf is_leaf,

(select count(*) from emp e

where e.mgr=a.empno

and a.mgr is not null

and rownum=1) is_branch,

decode(ename,connect_by_root(ename),1,0) is_root

from emp a start with mgr is null

connect by prior empno=mgr order by 4 desc,3 desc;

Note:标量子查询的应用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值