Oracle SQL 给定任何节点作为输入的完整层次结构
Oracle SQL full hierarchy given any node as input
我想在 Oracle SQL 数据库中创建一个完整的层次结构搜索查询。
我有一个关注 table,叫做 "item"。
id name parent_id
1 A NULL
2 B 1
3 C 2
4 D 3
5 E 2
输入是 id 列中的任何给定 id。它应该找到所有这个 id 的 children,它们的 children。还有 parents 和他们的 parents。
目前我有以下查询:
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(parent(parent_id 列为空)。否则它似乎正在工作。另外,如果可以简化我给定的查询,我也会很感激。
编辑
我想我通过以下查询得到了想要的结果:
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 值在查询之间发生变化,我无法将其添加为参数。也可以注释掉 start with m.id = 3 然后它将 return 所有项目之间的所有层次结构。有没有办法创建一些连接?例如:我会查询所有项目的所有这些关系,然后根据某些条件只获得某些项目关系。
如果你想将它用作视图,你可以执行以下操作:
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
将树的所有兄弟节点与根元素连接起来。然后你只需要使用这个查询两次并通过根元素连接它以获得通过 parent-child 关系连接的所有元素。
如果你想减少结果集,你可以使用 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)
例如,这将只为您提供起点的孩子和 parents,而不会提供其他叶子的条目。
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
我想在 Oracle SQL 数据库中创建一个完整的层次结构搜索查询。 我有一个关注 table,叫做 "item"。
id name parent_id
1 A NULL
2 B 1
3 C 2
4 D 3
5 E 2
输入是 id 列中的任何给定 id。它应该找到所有这个 id 的 children,它们的 children。还有 parents 和他们的 parents。 目前我有以下查询:
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(parent(parent_id 列为空)。否则它似乎正在工作。另外,如果可以简化我给定的查询,我也会很感激。
编辑
我想我通过以下查询得到了想要的结果:
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 值在查询之间发生变化,我无法将其添加为参数。也可以注释掉 start with m.id = 3 然后它将 return 所有项目之间的所有层次结构。有没有办法创建一些连接?例如:我会查询所有项目的所有这些关系,然后根据某些条件只获得某些项目关系。
如果你想将它用作视图,你可以执行以下操作:
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
将树的所有兄弟节点与根元素连接起来。然后你只需要使用这个查询两次并通过根元素连接它以获得通过 parent-child 关系连接的所有元素。
如果你想减少结果集,你可以使用 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)
例如,这将只为您提供起点的孩子和 parents,而不会提供其他叶子的条目。
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