一种方法可能是首先将缺失的层次结构从考虑product
中info
合并,然后生成结果......因为Product
并且info
具有与层次结构相关的数据,我们需要将它们组合起来。我认为这可能是最令人不安的部分。并非所有层次结构数据都在一个地方。一旦我意识到这一点,就需要一个工会来允许在工作之前进行连接。
因此,我们加入product
以info
获取所需的附加分层数据并将其合并到帐户表。这会产生一个包含所有需要的父子关系的数据集。
然后我们可以使用它connect by prior
来遍历层次结构。
SELECT a.id_acc, level as lvl
FROM (SELECT id_acc, parent_acc FROM account
UNION
SELECT P.Account_ID, i.account_id FROM info i
INNER JOIN product p
on I.Product_ID=P.Product_ID) A
START WITH A.ID_ACC=76543
CONNECT BY prior a.id_acc=a.parent_acc
这将返回:
Account Lvl
76543 1
18252 2
456452 3
34456 2
456567 2
注意:456452 存在于 18252 下,因此保持层次关系;暗示 76543 有 3 个孩子(18252、34456、456567),而 18252 有一个孩子 456452。
鉴于对您的问题的一些假设,我认为这是我能想到的最好的方法。
sys_connect_by_path
如果您需要知道完整路径 ( ) 或者如果数据中有循环需要消除 ( nocycle
) 或 isLeaf ( connect_by_isLeaf
) 以在层次结构中显示无子记录,则可以添加一些其他的花里胡哨。
SELECT a.id_acc
, level as lvl
, SYS_CONNECT_BY_PATH(ID_Acc, '/') "Path"
, CONNECT_BY_ISLEAF "IsLeaf"
FROM (SELECT id_acc, parent_acc FROM account
UNION
SELECT P.Account_ID, i.account_id
FROM info i
INNER JOIN product p
on I.Product_ID=P.Product_ID) A
START WITH a.id_acc=76543
CONNECT BY nocycle prior a.id_acc=a.parent_acc
这将导致类似:
ID_acc lvl Path isLeaf
76543 1 /76543 0
18252 2 /76543/18252 0
456452 3 /76543/18252/456452 1
34456 2 /76543/34456 1
456567 2 /76543/456567 1
有关功能的完整列表,请参阅Oracle Docs
我有点淡化了使用nocycle
. 如果数据中存在循环,您的结果可能不正确。
通过更多的工作,我们可以确定 to_Show 中涉及的顶层,尽管这样:
select distinct ID_ACC
from (SELECT id_acc, parent_acc FROM account
UNION
SELECT P.Account_ID, i.account_id
FROM info i
inner join product p
on i.product_id=p.product_id) a
where parent_acc is null
connect by prior a.parent_acc = a.id_acc
start with id_acc in (select id from to_show)
并将其与上述内容结合起来,无需硬编码即可获得所需的结果。
SELECT a.id_acc
, level as lvl
, SYS_CONNECT_BY_PATH(ID_Acc, '/') "Path"
, connect_by_isleaf "IsLeaf"
FROM (SELECT id_acc, parent_acc FROM account
UNION
SELECT P.Account_ID, i.account_id
FROM info i
INNER JOIN product p
on i.product_id=p.product_id) a
connect by nocycle prior a.id_acc=a.parent_acc
start with id_acc in
(
select distinct ID_ACC
from (SELECT id_acc, parent_acc FROM account
UNION
SELECT P.Account_ID, i.account_id
FROM info i
inner join product p
on i.product_id=p.product_id) a
where parent_acc is null
connect by prior a.parent_acc = a.id_acc
start with id_acc in (select id from to_show))
所以我们在这里所做的只是在子查询中使用 start with 来获取 to_Show 中每条记录的顶级域,并反转关系,所以我们向上爬而不是向下爬,然后使用不同的顶级域返回整个等级制度; 从而在 to_show 中显示节点;以及它所在的整个层次结构。
或作为 CTE(通用表表达式)以提高可读性和重构以消除重复。
with
--Let's combine the hierarchies so they are all in one place.
hsource as (
select id_acc, parent_acc from account
UNION
SELECT P.Account_ID, i.account_id
FROM info i
inner join product p
on i.product_id=p.product_id),
--Now lets get the top domain or root nodes of each item in To_Show
top_domain as (
select distinct id_acc
from (hSource) a
where parent_acc is null --this null compare is actually what tells us it's a root/Top domain! Assumption being all roots have null parent_Acc!
connect by prior a.parent_acc = a.id_acc
start with id_acc in (select id from to_show))
--Now lets use those top domains or root notes to render the hierarchy of each.
SELECT a.id_acc
, level as lvl
, SYS_CONNECT_BY_PATH(ID_Acc, '/') "Path"
, connect_by_isleaf "IsLeaf"
FROM (Select id_acc, parent_acc from hSource) a
connect by nocycle prior a.id_acc=a.parent_acc
start with id_acc in (Select ID_ACC from Top_Domain)
最后......如果我的假设parent_Acc
是 null 不正确,那么您需要将 top_domain 中的查询更改为以下内容: Connect by prior
假设顶层将为 null 否则您将获得循环数据,这就是为什么您不能简单地设置a.ID_ACC=a.parent_Acc
,所以我们只需使用 case 语句更改两个语句数据,以使 aParent_ACC is null
成为一个真实的语句。从技术上讲,该where
子句可能只是ID_ACC=parent_Acc
,但我想保持主题。但是,必须更改该connect by prior
行。当我说数据中没有循环时,请记住上面的内容......好吧,当这导致循环时。我的意思是来吧!我怎么能做自己的父母?但是我们使用 case 语句来处理它。ID_ACC=parent_ACC
with
--Let's combine the hierarchies so they are all in one place.
hsource as (
select id_acc, parent_acc from account
UNION
SELECT P.Account_ID, i.account_id
FROM info i
inner join product p
on i.product_id=p.product_id),
--Now lets get the top domain or root nodes of each item in To_Show
top_domain as (
select distinct a.id_acc
from (hsource) a
--Modification starts here...
where case when a.parent_acc =a.id_Acc then null else a.parent_Acc end is null
connect by prior (case when a.parent_acc=a.id_acc then null else a.parent_Acc end) = a.id_acc
--ends here
start with a.id_acc in (select id from to_show))
--Now lets use those top domains or root notes to render the hierarchy of each.
SELECT a.id_acc
, level as lvl
, SYS_CONNECT_BY_PATH(ID_Acc, '/') "Path"
, connect_by_isleaf "IsLeaf"
FROM (Select id_acc, parent_acc from hSource) a
connect by nocycle prior a.id_acc=a.parent_acc
start with id_acc in (Select ID_ACC from Top_Domain)