【问题标题】:PLSQL looping through hierarchyPLSQL 循环遍历层次结构
【发布时间】:2013-01-07 17:34:59
【问题描述】:

我想弄清楚如何循环遍历层次结构,我不知道如何放入 PLSQL。我想要实现的目标:我想知道在层次结构中比我高 10 级的是哪个部门:

假设我有一张桌子,上面有一个部门和一个上级部门。我要执行这种操作:

select my_department from table_departments as v_department
FOR counter in 1...9
LOOP
v_department:=
(SELECT parent_department
FROM table_department_hierarchy
WHERE child_department=v_department)
END LOOP as top_department;

我不知道正确的语法,有没有勇敢的灵魂可以帮助我?

【问题讨论】:

标签: plsql


【解决方案1】:

您使用正确的 PL/SQL 语法的方法类似于:

begin
  select my_department into v_department from table_departments;
  FOR counter in 1...9
  LOOP
    SELECT parent_department
    INTO v_department
    FROM table_department_hierarchy
    WHERE child_department=v_department;
  END LOOP:
END;

但是,您也许可以在这样的一个语句中获得所有信息:

SELECT parent_department
INTO v_department
FROM
( SELECT parent_department, level as lvl
  FROM table_department_hierarchy
  CONNECT BY child_department = PRIOR parent_department
  START WITH child_department = v_department
)
WHERE lvl = 9;

Oracle docs on hierarchical queries

【讨论】:

    【解决方案2】:

    这是我很久以前编写的一个大型 pl/sql 程序,旨在遍历员工/老板报告树一直到顶部(CEO)。这个版本是 Peoplesoft 特有的,但只要您阅读的内容在记录中具有父/子关系,它就可以在任何东西上工作......我还有其他更动态的版本,但这可能是最容易破译的。我删除了一些你不会关心的绒毛东西。此外,由于报告工具可以使用它,因此该特定解决方案会出于多种不同原因将其交付给表格...

    此外,它还动态确定级别,因此您不必像通过解决方案连接那样知道有多少级别。

    希望对你有帮助:

    CREATE OR REPLACE PROCEDURE DW."SPW_T_RESOURCE_HIERARCHY" (iCommit   In Integer Default 1000,
                                                         pdBegin   In Date Default trunc(Sysdate) - 3,
                                                         pdEnd     In Date Default trunc(Sysdate) + 1,
                                                         vTruncate In Varchar2 Default 'Y' ) Is
    
       ------------------------------------------------------
       --  DECLARATIONS
       ------------------------------------------------------
    
       Cursor curDataSource Is
    
       ---**********************************----
       ---****BEGIN CUSTOMIZE THIS BLOCK****----
       ---**********************************----
          Select
                    Eh.empl_id         F_DESCENDANT_ID
                   ,Eh.Super_Empl_Id   F_IMMEDIATE_ANCESTOR_ID
            From
                   Employee_Header EH
           Where
                   EH.SUPER_EMPL_ID IS NOT NULL OR EH.TERM_DATE IS NULL;
    
       ---**********************************----
       ---****END CUSTOMIZE THIS BLOCK******----
       ---**********************************----
    
       dNow              Date := Sysdate;
       iTotalRows        Integer := 0;
       iTotalErrors      Integer := 0;
    
       ---**********************************----
       ---****BEGIN CUSTOMIZE THIS BLOCK****----
       ---**********************************----
       vDescendentID     Varchar2(20);
       iDescendentLevel  Integer := 1;
       iAncestorLevel    Integer := 0;
       vAncestorID       Varchar2(20);
       vTmpAncestorID    Varchar2(20);
       vTmpEmployeeID    Varchar2(20);
    
       ---**********************************----
       ---****END CUSTOMIZE THIS BLOCK******----
       ---**********************************----
    
       ------------------------------------------------------
       -- END DECLARATIONS
       ------------------------------------------------------
    
       ------------------------------------------------------
       -- BEGIN MAIN
       ------------------------------------------------------
    Begin
       -- Loop over source records
       For recDataSource In curDataSource
       Loop
          iDescendentLevel := 1;
          vAncestorID := recDataSource.f_Immediate_Ancestor_Id;
    
          -- Start Transaction
          Begin
             while (Trim(vAncestorID) is not null)
             loop
                 Begin
                              -- Fetch Next Ancestor
                     Select EH.SUPER_EMPL_ID
                       Into vTmpAncestorID
                       From
                            EMPLOYEE_HEADER EH
                      Where
                            EH.EMPL_ID = vAncestorID;
                 Exception
                 When Others Then
                    vTmpAncestorID := null;
                 End;
    
                  If NVL(vTmpAncestorID,'-XYZ-') = NVL(vAncestorID,'-123-') Then
                     vTmpAncestorID := null;
                  End If;
    
                  vAncestorID := vTmpAncestorID;
                  iDescendentLevel := iDescendentLevel + 1;
             end loop;
    
             -- Insert Resource Base
             Insert Into T_RESOURCE_HIERARCHY
                (
                    T_RESOURCE_HIERARCHY.F_HIERARCHY_NAME,
                    T_RESOURCE_HIERARCHY.F_DESCENDANT_LEVEL,
                    T_RESOURCE_HIERARCHY.F_DESCENDANT_ID,
                    T_RESOURCE_HIERARCHY.F_ANCESTOR_LEVEL,
                    T_RESOURCE_HIERARCHY.F_ANCESTOR_ID
                )
             Values
                (
                    'Physical Org Chart',
                    iDescendentLevel,
                    recDataSource.f_Descendant_Id,
                    To_Number(Decode(iDescendentLevel,1,2,iDescendentLevel) - 1),
                    NVL(recDataSource.f_Immediate_Ancestor_Id,'ROOT')
                );
    
    
          -- Insert MySelf Into Resource Base as well for full hierarchy research
             Insert Into T_RESOURCE_HIERARCHY
                (
                    T_RESOURCE_HIERARCHY.F_HIERARCHY_NAME,
                    T_RESOURCE_HIERARCHY.F_DESCENDANT_LEVEL,
                    T_RESOURCE_HIERARCHY.F_DESCENDANT_ID,
                    T_RESOURCE_HIERARCHY.F_ANCESTOR_LEVEL,
                    T_RESOURCE_HIERARCHY.F_ANCESTOR_ID
                )
             Values
                (
                    'Physical Org Chart',
                    iDescendentLevel,
                    recDataSource.f_Descendant_Id,
                    iDescendentLevel,
                    NVL(recDataSource.f_Descendant_Id,'ROOT')
                );
    
          -- Now Its Time To Climb The Tree
          -- For This Employee
             vAncestorID := recDataSource.f_Immediate_Ancestor_Id;
             iAncestorLevel := iDescendentLevel-1;
             vTmpAncestorID := null;
    
             -- Loop over parents
             while (Trim(vAncestorID) is not null)
             loop
    
                 Begin
                     -- Fetch Next Ancestor
                     Select EH.SUPER_EMPL_ID
                       Into vTmpAncestorID
                       From
                            EMPLOYEE_HEADER EH
                      Where
                            EH.EMPL_ID = vAncestorID;
                 Exception
                 When Others Then
                    vTmpAncestorID := null;
                 End;
    
                 If NVL(vTmpAncestorID,'-XYZ-') = '-XYZ-' Then
                     vTmpAncestorID := null;
                 End If;
    
                  vAncestorID := vTmpAncestorID;
                  iAncestorLevel := iAncestorLevel - 1;
    
                 If vAncestorID is not null Then
                     -- Insert Resource Base
                     Insert Into T_RESOURCE_HIERARCHY
                        (
                            T_RESOURCE_HIERARCHY.F_HIERARCHY_NAME,
                            T_RESOURCE_HIERARCHY.F_DESCENDANT_LEVEL,
                            T_RESOURCE_HIERARCHY.F_DESCENDANT_ID,
                            T_RESOURCE_HIERARCHY.F_ANCESTOR_LEVEL,
                            T_RESOURCE_HIERARCHY.F_ANCESTOR_ID
                        )
                     Values
                        (
                           'Physical Org Chart',
                            iDescendentLevel,
                            recDataSource.f_Descendant_Id,
                            iAncestorLevel,
                            vAncestorID
    
                        );
                 End If;
             end loop;
    
    
             -- TRANSACTION EXCEPTION HANDLING
          Exception
             When Others Then
    
          End;
    
          -- ASSIGN HOW MANY RECORDS PROCESSED
          iTotalRows := curDataSource%Rowcount;
    
          -- CONDITIONAL/INCREMENTAL TRANSACTION COMMIT
          If Mod(iTotalRows, iCommit) = 0
          Then
             Commit;
          End If;
    
       End Loop;
    
    
       -- FINAL COMMIT AND MD UPDATE
       Commit;
    
    
       -- MAIN EXCEPTION HANDLING
    Exception
       When Others Then
          Begin
             iExceptionCode    := Sqlcode;
             vExceptionMessage := Sqlerrm;
             Raise_application_error(Sqlcode, Sqlerrm);
          End;
    
       ------------------------------------------------------
       -- END MAIN
       ------------------------------------------------------
    End SPW_T_RESOURCE_HIERARCHY;
    /
    

    【讨论】:

      【解决方案3】:

      请检查以下示例。未经测试,但相信:)

      DECLARE
      G_EMPLOYEE_ID NUMBER:=1880;
      FUNCTION GET_MANAGER(V_EMPLOYEE_ID NUMBER) RETURN NUMBER IS 
      V_MANAGER_ID NUMBER;
      BEGIN
        SELECT ID_MANAGER INTO V_MANAGER_ID FROM EMPLOYEES WHERE EMPLOYEE_ID = V_EMPLOYEE_ID;
        RETURN V_MANAGER_ID;
      EXCEPTION
        WHEN OTHERS THEN
        RETURN NULL;
      END;
      BEGIN
      LOOP 
      DBMS_OUTPUT.PUT_LINE('EMPLOYEE:' || G_EMPLOYEE_ID);
      G_EMPLOYEE_ID := GET_MANAGER(G_EMPLOYEE_ID);
      DBMS_OUTPUT.PUT_LINE('MANAGER:' || G_EMPLOYEE_ID);
      EXIT WHEN G_EMPLOYEE_ID IS NULL;
      END LOOP;
      END;
      

      另一个很好的选择(主要)是连接方式,开始

      【讨论】:

      • 你认为它也适用于这种情况吗? :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-28
      • 1970-01-01
      • 2012-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-07
      相关资源
      最近更新 更多