johanoa: NestedSets - Menüpfad

Hallo,

ich habe eine NestedSets-Tabelle mit left / right / level
Nun habe ich ein Wertetripel gegeben und möchte dazu folgende Datesätze ausgeben:

  • Die Kinder eine Ebene tiefer als der gegebene Knotenpunkte.
  • Die Geschwister zu jedem Knotenpunkt auf dem Pfad

Dies soll eine Navigation abgeben, die die relevanten Teile aufklappt.

Beispiel:

  • Hallo
  • hier
        - bin
        - ich
            - mit
            - ein paar
        - unterpunkten
            (- diese Kinder sollen nicht angezeigt werden)
  • tschüss

Sollte ausgegeben werden, wenn ich mich bei "ich" befinde.

Bisjetz habe ich einfach immer den kompletten Baum ausgelesen, was aber auch nicht schön ist.

Also habe ich es mit
SELECT p.*
    FROM tree n,
         tree p
   WHERE n.lft BETWEEN p.lft AND p.rgt
     AND n.id = 5
ORDER BY n.lft;
probiert. Hier fehlen mit natürlich die Geschwister jedes Knotenpunktes auf dem Pfad und die direkten Kinder.

Hat mir jemand einen Rat?

Gruß

  1. Hi,

    Geschwister eines Knotenpunktes haben immer eine markante Gemeinsamkeit: Right grenzt an Left. Ausserdem brauchst du UNION.

    Vielleicht solltest du dir das ganze mal in einem Diagramm visualisieren, wie die Werte genau aussehen in so einem Nested Set Baum mit mehreren Ebenen. Selbst mit einem Auge solltest du da gewisse Muster erkennen können.

    Gruss, Frank

  2. Hallo,

    Hallo johanoa

    ich habe eine NestedSets-Tabelle mit left / right / level

    Das Level solltest Du nicht speichern, das ist redundant und kann relativ leicht berechnet werden.

    Nun habe ich ein Wertetripel gegeben und möchte dazu folgende Datesätze ausgeben:

    • Die Kinder eine Ebene tiefer als der gegebene Knotenpunkte.
    • Die Geschwister zu jedem Knotenpunkt auf dem Pfad

    was meinst Du mit dem zweiten Punkt genau?

    Ich hätte das so verstanden, dass von dem "ich" aus nur

    - bin
        - ich
            - mit
            - ein paar
        - unterpunkten

    ausgegeben werden soll. Oder stimmt das nicht?

    SELECT p.*
        FROM tree n,
             tree p
       WHERE n.lft BETWEEN p.lft AND p.rgt
         AND n.id = 5
    ORDER BY n.lft;

    Das ist glaub ich nicht, was Du willst. Das gibt Dir nämlich alle Vorfahren Deines Knotens mit id 5. Du brauchst eher sowas

    SELECT n.id, count(*) -- das Zweite gibt Dir das Level, ggf. auch count(*) - 1
       FROM tree n,
            tree p
       WHERE n.lft BETWEEN p.lft AND p.rgt
         AND n.level = (das Level des knotens "ich" oder eins kleiner) -- in die Klammern muss ne entsprechende Unterabfrage)
    ORDER BY n.lft;

    Oder?

    Viele Grüße
    der Bademeister

    1. Hi Bademeister,

      ich habe eine NestedSets-Tabelle mit left / right / level
      Das Level solltest Du nicht speichern, das ist redundant und kann relativ leicht berechnet werden.

      Und wenn schon, die Persistierung dieser Information reduziert den "Berechnungs-"Aufwand bei globalen Abfragen auf den gesamten Baum durchaus signifikant. Vorallem, wenn man Datenbanksysteme hat, die keine Subqueries vertragen. Das Level als persistierte Information ist ein guter alternativer Eintrittspunkt in die Baumstruktur.

      CIao, Frank

      1. Hi Frank,

        Und wenn schon, die Persistierung dieser Information reduziert den "Berechnungs-"Aufwand bei globalen Abfragen auf den gesamten Baum durchaus signifikant.

        ... macht aber das Einfügen von Knoten in ca. gleichem Maße aufwendiger. Klar, im Falle dieses Menüs wird wohl nicht allzu oft was geändert, aber es  ist natürlich auch nicht sehr groß, daher ist auch der Rechenaufwand durch das Berechnen des Levels hier recht klein.

        Vorallem, wenn man Datenbanksysteme hat, die keine Subqueries vertragen.

        Wenn dem hier so ist, dann wäre das natürlich ein Problem, das stimmt.

        Also, Johanna, ich ziehe meine Empfehlung, Du sollest das Level nicht speichern, zurück und mache daraus nur den Hinweis, dass Du es nicht zwingend speichern musst, weil Du es berechnen kannst (wobei Du für Vergleiche von Leveln allerdings Subqueries brauchst).

        Viele Grüße an alle
        der Bademeister

  3. Hallo,

    also, dass ich die Ebene mitspeichere habe ich bewusst entschieden.

    left grenzt an right erscheint mir logisch nur muss ich ja jetzt irgendwie in der Abfrage formulieren, dass jeder Knotenpunkt auf dem Weg zum aktuellen left-Wert (auch Knotentpunkt 1) nach diesen Geschwistern durchgegangen wird. Mir fehlt etwas die Idee.

    Mit
    SELECT p.*
    FROM tree AS n
    INNER JOIN tree AS p
    ON (n.left BETWEEN p.left AND p.right
    AND (n.left = '12' OR n.level = '1'))
    GROUP BY p.left

    Bekomme ich alle Knoten der ersten Ebene, dies sind ja praktisch die Geschwister des ersten Knotenpunktes.
    Und ich bekomme den aktuellen Knoten selbst.
    Doch wie muss ich das jetzt anpacken, dass ich auf dem Weg dorthin die jeweiligen Geschwister möchte, die mit ihrem left an den right grenzen?

    Gruß

    1. Hallo,

      ich könnte auch den Pfad bis zum Knoten in einer ersten Abfrage herausfinden, sodass ich alle left- und right-Werte des Pfades bis zum aktuellen Knoten habe.

      Dann könnte ich für jedes left-right-Paar die Kinder, die höchstens eine Ebene tiefer liegen Abfragen.

      Aber dann benötige ich ja mehrere Abfragen, das kanns ja auch nicht sein.

      Ist es eventuell einfacher den Teilbaum beim umsetzen der Daten in eine Navigation umzusetzen? Jedoch würde mir auch hier die Idee, fehlen.

      Gruß

      1. Hallo,

        ich könnte auch den Pfad bis zum Knoten in einer ersten Abfrage herausfinden, sodass ich alle left- und right-Werte des Pfades bis zum aktuellen Knoten habe.

        nicht in einer ersten :-)

        a) Hast Du eine Abfrage, die Dir die Geschwister eines Knotens liefert?
        b) Noch besser wäre eine Abfrage, die Dir die Geschwister eines Knotens und den
           Knoten selbst liefert.

        Gehen wir von a) aus:

        Gib mir die
            Geschwisterknoten
            und ihr Level
        aller Knoten,
        die im Pfad des ausgewählten Knotens liegen (Subselect!)
        Verbinde dieses Ergebnis mit                (UNION)
        Gib mir die
            Knoten
            und ihr Level
        aller Knoten,
        die im Pfad des ausgewählten Knotens liegen

        Bei b) kannst Du auf die UNION verzichten:

        Gib mir
            die Knoten und ihre Geschwister,
            sowie ihr Level
        aller Knoten
        die im Pfad des ausgewählten Knotens liegen

        Sollte doch machbar sein.

        Freundliche Grüße

        Vinzenz

        1. Hallo,

          danke für deine Ausführungen.

          Nein ich habe keine Abfrage, die mir die Geschwister liefert. Da felht mir das Verständnis. Geschwister-left grenz an Aktuell-right und Geschwister-right an Aktuell-left währen die Ebene gleich sein muss. Aber das bekomme ich nicht abgefragt.

          Bis jetzt habe ich eine Abfrage, die mir den Pfad liefert (der angesprochene Subselect).

          Und eine Abfrage, die die direkten Kinder zu einem Knoten liefert.

          Diese zwei Abfragen verbinde ich aktuell für mein Vorhaben.

          Ich komme nicht dahinter, wie ich die Geschwister abfragen könnte.

          Gruß

          1. Hallo,

            Bis jetzt habe ich eine Abfrage, die mir den Pfad liefert (der angesprochene Subselect).
            Und eine Abfrage, die die direkten Kinder zu einem Knoten liefert.

            Diese zwei Abfragen verbinde ich aktuell für mein Vorhaben.

            ja, so geht es auch:

            Gib mir
                die direkten Kinder
            der Knoten,
            die sich im Pfad des aktuellen Knotens befinden
            und nicht der aktuelle Knoten selbst sind

            (weil es Deine Anforderung ist, dass die Kinder des aktuellen Knotens nicht angezeigt werden)

            Freundliche Grüße

            Vinzenz

    2. Hi,

      Mir fehlt etwas die Idee.

      Und mir fehlt langsam der Durchblick.Mach doch bitte mal endlich ne Zeichnung (möglichst nah an der Realität)

      • wie dein Baum aussieht
      • welche Knoten welche Left und Right Werte haben
      • welcher Knoten dein Abfrage-Einsprungspunkt ist  (bitte in Orange)
      • und welche Knoten du davon ausgehend im Ergebnis haben willst (bitte in Grün)

      Von der Zeichnung machst n Screenshot, lädst es auf irgendeinen Bilderhoster im Web hoch und verlinkst es hier. Dann kann man dir vielleicht gezielter helfen. Man sagt ja auch: Ein Bild sagt mehr als tausend Worte.

      Nebenbei: Unterabfragen (Subqueries) versteht dein Datenbanksystem? Und dein Datenbanksystem ist welches _genau_?

      Ciao, Frank