分层查询/基于 table 输入
Hierarchical Query / base on table input
帐号table:
ID_ACC PARENT_ACC
76543 76543 <-edit
18252 76543
34456 76543
456567 76543
457564 65424
45654242 6556756
信息table:
ID account_id product_id
875621 18252 98567
875621 34456 98567
产品table:
ACCOUNTID PRODUCT_ID
456452 98567
帐户 table 包含帐户 ID。但是一些帐户(ID_ACC)有parent个帐户(Parent_acc) - 这个例子表明
ID_ACC: 18252,
34456,
456567
具有相同的 parent_acc (76543)。
一些孩子有信息(信息table)
(本例表示18252和34456连接到信息table)
接下来,一些 info.account_id 包含产品 (Product table)(在本例中 - 只有 18252 accountid 具有产品,其帐号为:456452.)
Account.id_acc=Info.account_id
Info.product_id=Product_id.product_id
我想 select 所有帐户层次结构:
76543,
18252,
34456,
456567,
456452.
最难的(对我来说)是我需要基于table(展示)。如果 to_show table 由例如填充。 34456 然后帐户输出需要与上面的列表相同。
如果to_show table 由例如填充。 "76543,18252,34456"则同上,以此类推...
我所需要的只是呈现所有层次结构,无论哪个帐户(在产品 table 或信息或帐户中)在 to_show table 中......作为输入我可以从产品 table 获取 child/parent 或帐户。
我试图这样做,但不幸的是这对我来说太难了(因为我在层次结构查询中完全是新手......)。
伙计们,你能帮帮我吗?
create table account (
id_acc number,
parent_acc number
)
;
create table info
(
ID number,
Account_id number,
Product_id number
);
create table product (
Account_id number,
product_id number
);
create table to_show (
ID number
);
insert into account (id_acc,parent_acc)) values (76543,76543);
insert into account (id_acc,parent_acc) values (18252,76543);
insert into account (id_acc,parent_acc) values (34456,76543);
insert into account (id_acc,parent_acc) values (456567,76543);
insert into account (id_acc,parent_acc) values (457564,65424);
insert into account (id_acc,parent_acc) values (45654242,6556756);
insert into info values (875621,18252,98567);
insert into info values (875621,34456,null);
insert into product values (456452,98567);
insert into to_show values (34456);
一种方法可能是首先将 product
和 info
中缺少的层次结构结合起来,然后生成结果...因为 Product
和 info
有我们需要将它们组合到层次结构中的相关数据。我认为这可能是最令人不安的部分。并非所有层次结构数据都在一个地方。一旦我意识到这一点,就需要一个工会来允许在工作之前进行连接。
所以我们加入 product
到 info
以获得所需的额外分层数据并将其联合到帐户 table。这会导致包含所有需要的 parent child 关系的数据集。
然后我们可以使用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
这会 return:
Account Lvl
76543 1
18252 2
456452 3
34456 2
456567 2
注意:456452存在于18252下,所以保持层级关系;暗示 76543 有 3 children (18252, 34456, 456567) 和 18252 有 child 456452.
鉴于对您的问题的一些假设,我认为这是我能想到的最好的办法。
如果您需要知道完整路径 (sys_connect_by_path
) 或者如果数据中有循环需要消除 (nocycle
) 或 isLeaf,您可以添加一些其他的附加功能(connect_by_isLeaf
) 在层次结构中显示 child 较少的记录。
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 中每条记录的顶级域,并反转关系以便我们向上爬树而不是向下爬,然后使用return 整个层次结构的独特顶级域;因此显示 to_show 中的节点;以及它所在的整个层次结构。
或作为 CTE(通用 Table 表达式)以提高可读性和重构以消除重复。
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
为空的假设不正确,那么您需要将 top_domain 中的查询更改为以下内容:Connect by prior
假设top level 将为空,否则你会得到循环数据,这就是为什么你不能简单地设置 a.ID_ACC=a.parent_Acc
,所以我们只是使用 case 语句改变两个语句数据,使 Parent_ACC is null
成为一个真实的语句。从技术上讲,where
子句可以只是 ID_ACC=parent_Acc
,但我想保持主题不变。但是,connect by prior
行 必须 进行更改。记得上面我说过数据中没有循环……好吧,当 ID_ACC=parent_ACC
导致循环时。我的意思是来吧!我怎样才能成为我自己的parent?但是我们使用 case 语句来处理它。
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)
帐号table:
ID_ACC PARENT_ACC
76543 76543 <-edit
18252 76543
34456 76543
456567 76543
457564 65424
45654242 6556756
信息table:
ID account_id product_id
875621 18252 98567
875621 34456 98567
产品table:
ACCOUNTID PRODUCT_ID
456452 98567
帐户 table 包含帐户 ID。但是一些帐户(ID_ACC)有parent个帐户(Parent_acc) - 这个例子表明
ID_ACC: 18252,
34456,
456567
具有相同的 parent_acc (76543)。
一些孩子有信息(信息table)
(本例表示18252和34456连接到信息table)
接下来,一些 info.account_id 包含产品 (Product table)(在本例中 - 只有 18252 accountid 具有产品,其帐号为:456452.)
Account.id_acc=Info.account_id
Info.product_id=Product_id.product_id
我想 select 所有帐户层次结构:
76543,
18252,
34456,
456567,
456452.
最难的(对我来说)是我需要基于table(展示)。如果 to_show table 由例如填充。 34456 然后帐户输出需要与上面的列表相同。
如果to_show table 由例如填充。 "76543,18252,34456"则同上,以此类推...
我所需要的只是呈现所有层次结构,无论哪个帐户(在产品 table 或信息或帐户中)在 to_show table 中......作为输入我可以从产品 table 获取 child/parent 或帐户。 我试图这样做,但不幸的是这对我来说太难了(因为我在层次结构查询中完全是新手......)。 伙计们,你能帮帮我吗?
create table account (
id_acc number,
parent_acc number
)
;
create table info
(
ID number,
Account_id number,
Product_id number
);
create table product (
Account_id number,
product_id number
);
create table to_show (
ID number
);
insert into account (id_acc,parent_acc)) values (76543,76543);
insert into account (id_acc,parent_acc) values (18252,76543);
insert into account (id_acc,parent_acc) values (34456,76543);
insert into account (id_acc,parent_acc) values (456567,76543);
insert into account (id_acc,parent_acc) values (457564,65424);
insert into account (id_acc,parent_acc) values (45654242,6556756);
insert into info values (875621,18252,98567);
insert into info values (875621,34456,null);
insert into product values (456452,98567);
insert into to_show values (34456);
一种方法可能是首先将 product
和 info
中缺少的层次结构结合起来,然后生成结果...因为 Product
和 info
有我们需要将它们组合到层次结构中的相关数据。我认为这可能是最令人不安的部分。并非所有层次结构数据都在一个地方。一旦我意识到这一点,就需要一个工会来允许在工作之前进行连接。
所以我们加入 product
到 info
以获得所需的额外分层数据并将其联合到帐户 table。这会导致包含所有需要的 parent child 关系的数据集。
然后我们可以使用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
这会 return:
Account Lvl
76543 1
18252 2
456452 3
34456 2
456567 2
注意:456452存在于18252下,所以保持层级关系;暗示 76543 有 3 children (18252, 34456, 456567) 和 18252 有 child 456452.
鉴于对您的问题的一些假设,我认为这是我能想到的最好的办法。
如果您需要知道完整路径 (sys_connect_by_path
) 或者如果数据中有循环需要消除 (nocycle
) 或 isLeaf,您可以添加一些其他的附加功能(connect_by_isLeaf
) 在层次结构中显示 child 较少的记录。
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 中每条记录的顶级域,并反转关系以便我们向上爬树而不是向下爬,然后使用return 整个层次结构的独特顶级域;因此显示 to_show 中的节点;以及它所在的整个层次结构。
或作为 CTE(通用 Table 表达式)以提高可读性和重构以消除重复。
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
为空的假设不正确,那么您需要将 top_domain 中的查询更改为以下内容:Connect by prior
假设top level 将为空,否则你会得到循环数据,这就是为什么你不能简单地设置 a.ID_ACC=a.parent_Acc
,所以我们只是使用 case 语句改变两个语句数据,使 Parent_ACC is null
成为一个真实的语句。从技术上讲,where
子句可以只是 ID_ACC=parent_Acc
,但我想保持主题不变。但是,connect by prior
行 必须 进行更改。记得上面我说过数据中没有循环……好吧,当 ID_ACC=parent_ACC
导致循环时。我的意思是来吧!我怎样才能成为我自己的parent?但是我们使用 case 语句来处理它。
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)