PLSQL循环遍历层次结构

时间:2013-01-07 17:34:59

标签: plsql

我试图弄清楚如何循环遍历层次结构,我不知道如何放入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;

我无法弄清楚正确的语法,是否有勇敢的灵魂可以帮助我?

3 个答案:

答案 0 :(得分:2)

使用更正的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

答案 1 :(得分:0)

这是我很久以前编写的一个大型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;
/

答案 2 :(得分:0)

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

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;

另一个很棒的选择(主要)是CONNECT BY,START WITH