在 Oracle PL SQL 中 CONNECT_BY_ROOT 之后显示直接父级

Display immediate parent after CONNECT_BY_ROOT in Oracle PL SQL

我正在使用 oracle 12 数据库和客户端。在这方面需要帮助。我想填充一个在根之后显示根、子和直接父的列?让我们说“通过第二根连接”?

到目前为止,这是我的代码。

SELECT
          PARENT,
          CONNECT_BY_ROOT PARENT_ID AS ROOT_ID,
      ????2ND_ROOT_ID,
          CHILD_ID AS CHILD_ID 
     FROM TABLE
     START WITH 
        PARENT_ID = 1 
     CONNECT BY
         PRIOR CHILD_ID =  PARENT_ID  

输入

PARENT_ID   CHILD_ID
1           1.1
1           1.2
1.1         1.1.1
1.1         1.1.2
1.1         1.1.3
1.1         1.1.4
1.1         1.1.5
1.2         1.2.1
1.2         1.2.2
1.1.1       1.1.1.1
1.1.1       1.1.1.2
1.1.3       1.1.3.1
1.1.3       1.1.3.2
1.1.3       1.1.3.3

输出:

ROOT_ID  2ND_ROOT_ID    CHILD_ID
    1        1.1        1.1
    1        1.2        1.2
    1        1.1        1.1.1
    1        1.1        1.1.2
    1        1.1        1.1.3
    1        1.1        1.1.4
    1        1.1        1.1.5
    1        1.2        1.2.1
    1        1.2        1.2.2
    1        1.1        1.1.1.1
    1        1.1        1.1.1.2
    1        1.1        1.1.3.1
    1        1.1        1.1.3.2
    1        1.1        1.1.3.3

还尝试使用通过路径连接的子字符串

regexp_substr(SYS_CONNECT_BY_PATH, ....

要在 root 之后获取父级,但它会给我一个 ORA-01489 错误。

请提前多多指教

您可以使用条件 sys_connect_by_path:

rtrim(sys_connect_by_path(case when level<=2 then id else null end, '.'),'.') 

这可以使用 LEVEL 关键字来解决。 LEVEL 显示每个记录在层次结构中相对于根的位置或级别。因此,在经典的 EMPLOYEE table 中,如果员工 Jake 具有以下层次结构:

杰克 -> 杰克的经理 -> 副总裁 -> 首席执行官

然后 Jake 在 LEVEL 1,Manager 在 LEVEL 2,VP 在 LEVEL 3,CEO 在 LEVEL 4。

您要的是简单地选择所有第 4、3 和 1 级记录,这将为您提供根、第二根和记录本身。但是有一个问题 - LEVEL 编号从底部开始,而不是从顶部开始。因此,您不知道给定员工的根处于什么级别。它可以是 2、3、4、5 或任何数字,具体取决于层次结构中的级别数。

在 Oracle 中,CONNECT_BY_ROOT 提供根记录,但获得第二个根并不简单。

这就是为什么下面的查询使用 ROW_NUMBER() 分析函数来恢复级别的顺序 以便根变为 LEVEL 1,第二个根变为 LEVEL 2 并且很快。如果 root 始终处于 LEVEL 1 并且 root 的直接子级始终处于 LEVEL 2,那么针对这两者编写 WHERE 子句就变得容易了。

当您像这样使用 CONNECT BY 时,每个关系都有一个单独的记录。在下面的 WITH 子句中,员工 Jake 拥有的记录数量与他拥有的上至 CEO 的经理数量一样多。所以 Jake -> Jake 的经理有记录。 Jake -> Jake's Manager->VP has a record.. 依此类推,所有属于员工 Jake 的记录。

下面的 EMP WITH 子句使用 ROW_NUMBER() 为每个从 1 开始的关系记录分配增量行号作为根。对于下一位员工,它再次从 1 开始。

EMP_PIVOT 通过使用上一步的 ROW_NUMBER() 计算旋转经理姓名来创建一个新列。

WITH EMP AS
(
SELECT E.employee_id, E.employee_name, E.designation, 
CONNECT_BY_ROOT E.employee_name as Manager_name, 
CONNECT_BY_ROOT E.designation as Manager_Designation, 
LEVEL EMP_LEVEL,
ROW_NUMBER() OVER(PARTITION BY EMPLOYEE_ID ORDER BY LEVEL DESC) LEVEL_HIERARCHY
FROM Employee E
CONNECT BY PRIOR E.employee_id = E.manager_id
ORDER BY 1
),
EMP_PIVOT AS
(
SELECT
MAX(DECODE(EMP.LEVEL_HIERARCHY,1,EMP.MANAGER_NAME, NULL)) OVER(PARTITION BY EMPLOYEE_ID) AS ROOT_MGR,
EMP.MANAGER_NAME AS SECOND_ROOT_MGR, 
EMP.EMPLOYEE_NAME,
LEVEL_HIERARCHY
FROM EMP 
WHERE EMP.LEVEL_HIERARCHY <=2 )

SELECT * FROM EMP_PIVOT WHERE LEVEL_HIERARCHY=2;

输出:

最后一个 WHERE 条件设置为 LEVEL_HIERARCHY=2 因此我们只为每个员工获取一条记录,其中包含我们需要的所有 3 列。