2016-08-13 7 views
1

私は、二重または三重親を持ついくつかのキーがある階層データを扱っています。共有メンバー(二重親メンバー)を持つOracle階層

階層を表す階層クエリを作成する必要がありますが、この2重または3重の親キーはツリー内に単独で表示され、その子は3つのキーの最初のキーでのみ表示されます。

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する必要があります。だから私が「*」と書いたものは現れてはいけません。

私はこの二重の親キーを特定し、これに基づいて行を除外する二次照会を作成することができます。 しかし、それを行う最短の方法があるかどうか疑問に思っています。ハイライトそのものを使って作業しています...もし既にキーが別の親を持っていることを知る方法があれば。 (これはビューになるので、PL/SQLではなくクエリでこれを行う必要があります)

ありがとうございます。

+0

「最初の」発生とはどういう意味ですか?結果セット内の行は順序付けされていません(バスケットの中のボールのようなものです)ので、質問はあまり意味がありません。結果セットのすべての行は、(おそらく論理的にはベクトル化された処理によって物理的にも)同時に生成されます。だから、あなたが「最初」の意味を明確にしても、1回のパスでこれを行うことはできません。 – mathguy

答えて

2

私は一般的にsql-serverだと思います。これはあなたのための考えですが、いくつかの微調整と構文のヘルプが必要な場合があります。しかし、子レベルで分割されたROW_NUMBER()を追加し、再帰を制限するためにconnect by節に2番目の条件を追加するとどうでしょうか。おそらくこのような何か?

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でPARTIENTを次のように追加します。PARTITION BY CHILD、PARENT。これにより、各子親の1つのランダムコピーが保持されますが、特定のものが必要な場合は、 – mathguy

関連する問題