2016-08-13 6 views
1

Ich arbeite mit hierarchischen Daten, in denen es einige Schlüssel gibt, die doppelte oder dreifache Eltern hat.Oracle-Hierarchie mit freigegebenen Mitgliedern (doppelte Eltern)

Ich muss eine hierarchische Abfrage schreiben, um die Hierarchie darzustellen, aber diese doppelten oder dreifachen Elternschlüssel müssen allein in der Baumstruktur angezeigt werden. Die Anzeige ihrer Kinder ist nur im ersten Schlüssel der drei erlaubt.

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 

;

Das Ergebnis dieser Abfrage ist dies, aber es ist nicht genau das, was ich versuche zu bekommen:

---------- 
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* 

Reihen D-C und E-D sollten nur in dem ersten Auftreten von „C“ -Taste displayin werden. Diejenigen, die ich mit "*" markiert habe, sollten nicht erscheinen.

Ich weiß, dass ich nur eine sekundäre Abfrage erstellen konnte, in der ich diese Doppel-Eltern-Schlüssel erkennen und Zeilen auf dieser Basis ausschließen. Aber ich frage mich, ob es einen kürzesten Weg dazu gibt, mit der Hierarchie selbst zu arbeiten .... wenn es eine Möglichkeit gibt zu wissen, dass ein Schlüssel bereits einen anderen Elternteil hat. (Da dies in einer Ansicht geht, muss ich dies in einer Abfrage, nicht PL/SQL.)

Vielen Dank im Voraus.

+0

Was meinen Sie mit "ersten" Auftreten? Zeilen in einer Ergebnismenge sind nicht geordnet (sie sind wie Bälle in einem Korb), daher macht die Frage keinen Sinn. Alle Zeilen in der Ergebnismenge werden gleichzeitig erzeugt (vielleicht sogar physikalisch durch vektorisierte Verarbeitung und in jedem Fall logisch). Selbst nachdem Sie geklärt haben, was Sie mit "zuerst" meinen, ist es unwahrscheinlich, dass Sie dies in einem Durchgang tun können. – mathguy

Antwort

2

Ich gebe zu, ich bin in der Regel sql-Server, also ist dies ein Gedanke für Sie, aber es kann einige Optimierung und Syntax Hilfe benötigen. Aber was ist mit dem Hinzufügen einer ROW_NUMBER() Partition auf Child-Ebene und Hinzufügen einer zweiten Bedingung in Ihrer Connect-by-Klausel, um die Rekursion zu begrenzen. Vielleicht so etwas?

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

Beeindruckend !, danke .... ziemlich nah .... aber diese Lösung wird auch die Zeilen C-G und C-Z verschwinden lassen, und diese sollten im Bericht erscheinen. Nur ihre Kinder sollten ausgeschaltet sein .... :( –

+0

@CraigStevensson - das ist (fast) die richtige Lösung in Oracle, aber ich dachte, Ihre Anforderung war speziell eine "sekundäre Abfrage" zu vermeiden. Diese Lösung (und wahrscheinlich alle anderen möglichen Lösung) verwendet eine sekundäre Abfrage.Hoffen, dass Sie damit einverstanden sind (anscheinend Sie sind). – mathguy

+0

@CraigStevensson - um diese Lösung für Oracle zu beheben, ändern Sie in der Definition von ROW_NUMBER() ORDER BY (SELECT 0) einfach ORDER BY 0 (oder ORDER BY NULL), und in PARTITION BY CHILD fügen Sie PARENT wie folgt hinzu: PARTITION BY CHILD, PARENT. Dies wird eine RANDOM-Kopie von jedem Kind-Elternteil behalten, wenn Sie eine bestimmte wollen, müssen Sie bestimmen, welche Reihenfolge (verwenden Sie es in ORDER BY) – mathguy

Verwandte Themen