2016-08-13 79 views
1

我正在使用其中有一些具有雙父母或三父母的鍵的分層數據。帶有共享成員的Oracle層次結構(雙父成員)

我必須編寫一個分層查詢來表示層次結構,但是這個雙重或三重父鍵必須單獨出現在樹中,顯示它們的子項只允許在三個中找到的第一個鍵中。

WITH HER(CHILD, PARENT) AS (
    SELECT 'A' AS CHILD, null AS PARENT FROM DUAL UNION 
    SELECT 'B' AS CHILD, 'A' AS PARENT FROM DUAL UNION 
    SELECT 'C' AS CHILD, 'A' AS PARENT FROM DUAL UNION 
    SELECT 'D' AS CHILD, 'C' AS PARENT FROM DUAL UNION 
    SELECT 'E' AS CHILD, 'D' AS PARENT FROM DUAL UNION 
    SELECT 'F' AS CHILD, null AS PARENT FROM DUAL UNION 
    SELECT 'G' AS CHILD, 'F' AS PARENT FROM DUAL UNION 
    SELECT 'C' AS CHILD, 'G' AS PARENT FROM DUAL UNION --<<--- shared 
    SELECT 'H' AS CHILD, null AS PARENT FROM DUAL UNION 
    SELECT 'B' AS CHILD, 'H' AS PARENT FROM DUAL UNION --<<--- shared 
    SELECT 'X' AS CHILD, null AS PARENT FROM DUAL UNION 
    SELECT 'Y' AS CHILD, 'X' AS PARENT FROM DUAL UNION 
    SELECT 'Z' AS CHILD, 'Y' AS PARENT FROM DUAL UNION 
    SELECT 'C' AS CHILD, 'Z' AS PARENT FROM DUAL  --<<--- shared 
    ) 
    SELECT 
     LPAD(' ', 7*(LEVEL-1),' ')||CHILD||' - '||PARENT 
    FROM HER 
    START WITH PARENT IS NULL 
    CONNECT BY PRIOR CHILD = PARENT 

;

從該查詢結果是這樣的,但它不是正是我試圖讓:

---------- 
A - 
     B - A 
     C - A 
       D - C 
        E - D 
F - 
     G - F 
       C - G 
        *D - C* 
          *E - D* 
H - 
     B - H 
X - 
     Y - X 
       Z - Y 
        C - Z 
          *D - C* 
            *E - D* 

行d-C和E-d應該只在「C」鍵的首次亮相被displayin。所以那些標有「*」的應該不會出現。

我知道我可以創建一個輔助查詢,在這個輔助查詢中我發現了這個雙親鍵,然後根據這個排除了行。 但是我不知道是否有最短的方法來做到這一點,與hiearchy本身一起工作....如果有一種方法可以知道一個密鑰已經有另一個父母。 (因爲這是一個視圖,我需要在查詢中這樣做,而不是PL/SQL。)

在此先感謝。

+0

你是什麼意思由「第一」發生?結果集中的行沒有排序(它們就像籃子裏的球),所以這個問題沒有多大意義。結果集中的所有行都是同時生成的(甚至可能是通過矢量化處理實現的,而且在任何情況下都是邏輯上的)。所以,即使在您澄清「第一」的含義之後,您也不太可能一次完成此操作。 – mathguy

回答

2

我承認我一般是sql-server,所以這是一個想法,但它可能需要一些調整和語法幫助。但是如何添加一個ROW_NUMBER()在Child級別分區,並在connect by子句中添加第二個條件來限制遞歸。也許這樣?

WITH HER(CHILD, PARENT) AS (
    SELECT 'A' AS CHILD, null AS PARENT FROM DUAL UNION 
    SELECT 'B' AS CHILD, 'A' AS PARENT FROM DUAL UNION 
    SELECT 'C' AS CHILD, 'A' AS PARENT FROM DUAL UNION 
    SELECT 'D' AS CHILD, 'C' AS PARENT FROM DUAL UNION 
    SELECT 'E' AS CHILD, 'D' AS PARENT FROM DUAL UNION 
    SELECT 'F' AS CHILD, null AS PARENT FROM DUAL UNION 
    SELECT 'G' AS CHILD, 'F' AS PARENT FROM DUAL UNION 
    SELECT 'C' AS CHILD, 'G' AS PARENT FROM DUAL UNION --<<--- shared 
    SELECT 'H' AS CHILD, null AS PARENT FROM DUAL UNION 
    SELECT 'B' AS CHILD, 'H' AS PARENT FROM DUAL UNION --<<--- shared 
    SELECT 'X' AS CHILD, null AS PARENT FROM DUAL UNION 
    SELECT 'Y' AS CHILD, 'X' AS PARENT FROM DUAL UNION 
    SELECT 'Z' AS CHILD, 'Y' AS PARENT FROM DUAL UNION 
    SELECT 'C' AS CHILD, 'Z' AS PARENT FROM DUAL  --<<--- shared 
    ) 

    , HERChildRowNum(CHILD, PARENT, ChildRowNum) AS (

     SELECT 
      CHILD, 
      PARENT, 
      ROW_NUMBER() OVER (PARTITION BY CHILD ORDER BY (SELECT 0)) as ChildRowNum 
     FROM 
      HER 
    ) 


    SELECT 
     LPAD(' ', 7*(LEVEL-1),' ')||CHILD||' - '||PARENT 
    FROM HERChildRowNum 
    START WITH PARENT IS NULL 
    CONNECT BY PRIOR CHILD = PARENT AND (PRIOR ChildRowNum = ChildRowNum OR ChildRowNum>1) 
+0

令人印象深刻!,感謝....非常接近....但這種解決方案也會消除行C-G和C-Z,並且這些應該出現在報告中。他們的子女應該離開...... :( –

+0

@CraigStevensson - 這是(幾乎)在Oracle中的正確解決方案,但我認爲你的要求是專門避免「輔助查詢」。此解決方案(可能還有其他任何可能的解決方案)確實使用了輔助查詢,希望你確定(顯然是你)。 – mathguy

+0

@CraigStevensson - 爲Oracle解決這個解決方案,在ROW_NUMBER()的定義中將ORDER BY(SELECT 0)改爲簡單的ORDER BY 0 (或ORDER BY NULL),並在PARTITION BY CHILD中添加父項,如下所示:PARTITION BY CHILD,PARENT。這將保留每個子父項的一個RANDOM副本;如果您想要特定的副本,則必須確定排序應爲 – mathguy