2013-01-07 156 views
0

我想弄清楚如何通過層次循環,我不知道如何放入PLSQL。我試圖達到的目標:我想知道哪個部門在層次結構中高於我10步:PLSQL循環層次結構

假設我有一個包含部門和父級部門的表。我想執行這樣的操作:

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; 

我找不出正確的語法,是否有勇敢的靈魂在那裏誰可以幫助我?

+1

你可能想看看CONNECT BY語法,解釋和例子在這裏:HTTP:// psoug.org/reference/connectby.html –

+0

不需要PL/SQL代碼,您可以使用遞歸查詢。 –

回答

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

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; 
/
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

+0

你認爲它也適用於這種情況嗎? :) – clq