[英]Oracle SQL full hierarchy given any node as input
我想在Oracle SQL数据库中创建一个完整的层次搜索查询。 我有一张下表,称为“项目”。
id name parent_id
1 A NULL
2 B 1
3 C 2
4 D 3
5 E 2
输入是id列中任何给定的id。 它应该找到此id的所有孩子,即他们的孩子。 以及父母及其父母。 目前,我有以下查询:
select distinct m.id, m.parent_id
from item m
connect by prior m.id = m.parent_id
start with m.parent_id IN (
select m.parent_id
from item m
connect by m.id = prior m.parent_id
start with m.id = 3
union
select m.parent_id
from item m
where m.parent_id = 3);
目前,它似乎仅在起作用,因此未选择没有父项的父项(parent_id列为null)。 否则,它似乎正在工作。 另外,如果我给定的查询可以简化,我也将不胜感激。
编辑
我认为我通过以下查询获得了预期的结果:
select m.id
from item m
start with m.id in (
select m.id
from item m
where connect_by_isleaf = 1
start with m.id = 3
connect by m.id = prior m.parent_id
)
connect by m.parent_id = prior m.id;
现在有下一个问题。 从m.id = 3开始 。 问题是我想根据整个查询创建一个视图。 但是随着m.id值在查询之间的变化,我无法将其添加为参数。 也可以注释掉以m.id = 3开头的内容 ,然后它将返回所有项目之间的所有层次结构。 有没有办法创建一些联接? 例如:我将查询所有项目的所有那些关系,然后通过某种条件仅获得某些项目的关系。
如果要将其用作视图,可以执行以下操作:
WITH rek AS (SELECT item.id
, item.name
, connect_by_root item.id root_id
FROM item
START WITH parent_id IS null
CONNECT BY NOCYCLE parent_id = PRIOR id)
SELECT startItem.id startId
, startItem.name startName
, childItem.id childID
, childItem.name childName
FROM rek startItem
JOIN rek childItem
USING (root_id)
-- WHERE startItem.id = 3 -- This would be done from outside the view
子查询rek
将树的所有同级与根元素连接起来。 然后,您只需要使用两次此查询,然后通过根元素将其连接即可获取通过父子关系连接的所有元素。
如果要减少结果集,可以使用SYS_CONNECT_BY_PATH
这样做:
WITH rek AS (SELECT item.id
, item.name
, connect_by_root item.id root_id
, SYS_CONNECT_BY_PATH(item.id, '/') path
FROM item
START WITH parent_id IS null
CONNECT BY NOCYCLE parent_id = PRIOR id)
SELECT startItem.id startId
, startItem.name startName
, childItem.id childID
, childItem.name childName
, childItem.path
FROM rek startItem
JOIN rek childItem
ON startItem.root_id = childItem.root_id
AND (startItem.path LIKE childItem.path||'/%'
OR childItem.path LIKE startItem.path||'/%'
OR childItem.id = startItem.id)
例如,这将仅给您您的孩子和父母的起点,而没有其他叶子的条目。
Oracle安装程序 :
CREATE TABLE item ( id, name, parent_id ) AS
SELECT 1, 'A', NULL FROM DUAL UNION ALL
SELECT 2, 'B', 1 FROM DUAL UNION ALL
SELECT 3, 'C', 2 FROM DUAL UNION ALL
SELECT 4, 'D', 3 FROM DUAL UNION ALL
SELECT 5, 'E', 2 FROM DUAL;
您可以使用以下方法获取该物品及其所有祖先:
SELECT *
FROM item
START WITH id = 2
CONNECT BY PRIOR parent_id = id
您可以使用以下命令获取该项目的所有后代:
SELECT *
FROM item
START WITH parent_id = 2
CONNECT BY PRIOR id = parent_id
您可以使用UNION ALL
将两者结合起来。 但是,这将匹配的项放在先,然后按照祖先的顺序排列祖先,然后按照后代递减的顺序排列后代……这可能会造成混淆。
因此,您可以对查询重新排序,以使两者保持一致的顺序:
SELECT *
FROM (
SELECT *
FROM item
START WITH id = 2
CONNECT BY PRIOR parent_id = id
ORDER BY LEVEL DESC
)
UNION ALL
SELECT *
FROM (
SELECT *
FROM item
START WITH parent_id = 2
CONNECT BY PRIOR id = parent_id
ORDER SIBLINGS BY name
);
输出 :
ID NAME PARENT_ID
-- ---- ---------
1 A -
2 B 1
3 C 2
4 D 3
5 E 2
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.