Ausgabe von Bäumen mit Vater-Zeiger

qsrs

Erfahrenes Mitglied
Hallo,

ich habe eine relativ einfache Methode gewählt, um Kategorien in einer Datenbank zu speichern, und sie dann in einer Baumstruktur zu pflegen.

Die SQL-Tabelle sieht so aus:

id | category_name | parent_id |
1 | Hauptkat. 1 | 0 |
2 | Hauptkat. 2 | 0 |
3 | 1. Sub von Hauptkat. 1 | 1 |
4 | 2. Sub von Hauptkat. 1 | 1 |

Um zu Navigieren, verwende ich folgenden Code:

PHP:
$sql0 = "SELECT * FROM `cat_test` WHERE `parent_id` = '$parent_id' ORDER BY `category`";
$query0 = mysql_query ($sql0, $dbconnect);
for ($i1 = 0; $i1 < mysql_num_rows ($query0); $i1++) {
 $array0[$i1] = mysql_fetch_array ($query0);
 }
for ($i1 = 0; $i1 < count ($array0); $i1++) {
 echo "<a href=\"test2.php?parent_id=".$array0[$i1][id]."\">".$array0[$i1][category]."</a><br>";
 }

Soweit funktioniert alles. Jetzt die Frage. Ich bin mir nicht sicher, ob es bei dieser Variante des Speicherns in der Datenbank, also mit einer parent_id, zu Problemen beim Auslesen des "Gesamtbaumes" kommt, und ob das überhaupt möglich ist. Ich habe nämlich Folgendes vor: ich möchte in einem <select>-Feld alle Kategorien und Unterkategorien ausgeben, und zwar so:

Hauptkat. 1
Hauptkat. 1/1. Sub von Hauptkat. 1
Hauptkat. 1/2. Sub von Hauptkat. 1
Hauptkat. 2

Ich möchte damit ermöglichen, den einzelnen Kategorien und Unterkategorien neue hinzuzufügen. Geht das mit dieser Speichermethode, und falls ja, wie wäre denn der Ansatz.

Ich weiß, dass Nested Sets evtl. die bessere Wahl ist. Ich bin in Sachen SQL jedoch noch etwas neu und möchte mich erst Schritt für Schritt hocharbeiten. Nested Sets ist für mein Vorhaben wahrscheinlich ohnehin etwas zu viel, ich denke die aktuelle Methode müsste erst einmal reichen. BTW, was sind denn die Nachteile dieser Methode und v.a. warum?
 
Zuletzt bearbeitet:
Hallo qsrs,

wie viele Ebenen besitzt denn deine Hierarchie? Wenn es wie im Beispiel garantiert immer nur zwei Ebenen gibt, dann sollte die jetzige Tabellenstruktur noch ausreichen. Ansonsten müsstest du dir entweder alle Datensätze der Tabelle holen und die Hierarchie in PHP erstellen oder die jeweiligen Kindobjekte rekursiv abfragen (was allgemein langsam und damit nicht zu empfehlen ist - das wäre dann auch schon eines der Nachteile dieser Repräsentation eines Baumes).

Grüße,
Matthias
 
Hallo Matthias,

danke für deine Antwort. Die Tiefe sollte variabel sein, könnte theoretisch auch unendlich werden, ist aber eher unwahrscheinlich. Es werden vielleicht maximal 10 Ebenen sein. Wie könnte das in PHP ungefähr aussehen mit der Hierarchie? Wären dann Nested Sets doch eher geeignet, und gibt es außer dieser Methode noch andere? Die Lösung mit der parent_id scheint mir für meinen Anfänger-Status doch im Moment die, mit der ich mich einmal zuerst auseinander setzen sollte, notfalls muss ich mich doch schon mit Nested Sets beschäftigen. Mich würde aber doch noch interessieren, wie der Ansatz mit PHP wäre, eine Hierarchie zu erstellen. Die Darstellung der Hierarchie, wie im Code oben, ist für mein Projekt genau richtig und ausreichend. Nur beim Hinzufügen der einzelnen Kategorien scheinen die ersten Probleme aufzutreten, da ich hier dann doch eine komplette Baumstruktur anzeigen möchte/muss.
 
Hallo,

Die Tiefe sollte variabel sein, könnte theoretisch auch unendlich werden, ist aber eher unwahrscheinlich. Es werden vielleicht maximal 10 Ebenen sein. Wie könnte das in PHP ungefähr aussehen mit der Hierarchie?
Eine Möglichkeit findest du in einem früheren Thread zu diesem Thema.

Wären dann Nested Sets doch eher geeignet, und gibt es außer dieser Methode noch andere?
Bei bis zu 10 Ebenen würde ich schon zu Nested Sets raten.

Die Lösung mit der parent_id scheint mir für meinen Anfänger-Status doch im Moment die, mit der ich mich einmal zuerst auseinander setzen sollte, notfalls muss ich mich doch schon mit Nested Sets beschäftigen.
Lies dir einfach mal den Artikel „Storing Hierarchical Data in a Database“ (englisch) durch. Wenn man das Grundprinzip verstanden hat, ist es eigentlich nicht mehr allzuschwer. Zumal die Erzeugung einer Hierarchie aus einer Liste mit Elternverweisen in PHP auch nicht trivial ist.

Grüße,
Matthias
 
Danke Matthias,

ich sehe mir beides einmal an. Denke, ich beschäftige mich am Besten gleich mit Nested Sets. Vielen Dank.
 
Hallo (Matthias),

der Artikel „Storing Hierarchical Data in a Database“ ist wirklich gut. Sehr verständlich, obwohl ich natürlich noch nicht mit allem 100% vertraut bin.

Ich habe dazu aber konkret eine Frage und zwar zum Hinzufügen von Knoten. Es soll laut dem Artikel ein weiterer Knoten als child von "Red" hinzugefügt werden ("Strawberry"). Jetzt wird erst einmal Platz geschaffen:

UPDATE tree SET rgt=rgt+2 WHERE rgt>5;
UPDATE tree SET lft=lft+2 WHERE lft>5;

und dann das Insert:

INSERT INTO tree SET lft=6, rgt=7, title='Strawberry';

Und hier meine Frage. Ist das nicht falsch? Wenn "Red" als linken Wert 3 hat und als rechten Wert 6, und das Child "Cherry" den linken Wert 4 und den rechten 5, müsste dann der neu hinzugefügte Knoten "Strawberry" nicht als linken Wert 5 und als rechten den Wert 6 haben? Dann müsste das Update doch so aussehen:

UPDATE tree SET rgt=rgt+2 WHERE rgt>4;
UPDATE tree SET lft=lft+2 WHERE lft>4;

und dann das Insert:

INSERT INTO tree SET lft=5, rgt=6, title='Strawberry';

Jedenfalls hat das bei mir auch funktioniert. Da ich dem Artikel jedoch einfach mal traue das er richtig ist, frage ich mich nun, wo mein Denkfehler ist. Es wird ja oft auch als Wurm-Modell beschrieben, und so müsste dann doch auch das Update gemacht werden, oder nicht?
 
Hallo,

Ich habe dazu aber konkret eine Frage und zwar zum Hinzufügen von Knoten. Es soll laut dem Artikel ein weiterer Knoten als child von "Red" hinzugefügt werden ("Strawberry"). Jetzt wird erst einmal Platz geschaffen:

UPDATE tree SET rgt=rgt+2 WHERE rgt>5;
UPDATE tree SET lft=lft+2 WHERE lft>5;

und dann das Insert:

INSERT INTO tree SET lft=6, rgt=7, title='Strawberry';

Und hier meine Frage. Ist das nicht falsch?
Nein, das ist schon richtig so. Der neue Knoten soll ja ein Kind von „Red“ sein und rechts neben „Cherry“ stehen.

Wenn "Red" als linken Wert 3 hat und als rechten Wert 6, und das Child "Cherry" den linken Wert 4 und den rechten 5, müsste dann der neu hinzugefügte Knoten "Strawberry" nicht als linken Wert 5 und als rechten den Wert 6 haben? Dann müsste das Update doch so aussehen:

UPDATE tree SET rgt=rgt+2 WHERE rgt>4;
UPDATE tree SET lft=lft+2 WHERE lft>4;

und dann das Insert:

INSERT INTO tree SET lft=5, rgt=6, title='Strawberry';
Dann wird „Strawberry“ allerdings als Kind von „Cherry“ eingeordnet. Die Intention war aber, „Strawberry“ zum Kind von „Red“ und somit zum Geschwister von „Cherry“ zu machen.

Grüße,
Matthias
 
Hallo,

mache gerade die ersten Übungen und Gehversuche mit Nested Sets. Habe ein kleines Problem und anschließend noch eine Frage. Nun zum Problem. Wie bereits oben beschrieben, versuche ich in einem Select-Feld den Baum auszugeben. Ich habe dazu den Beispielcode des Artikels verwendet. Bei einfacher Ausgabe funktioniert alles problemlos. Nur, wenn ich es in einem Select-Feld versuche, klappt es nicht. Hier die Funktion und mein Versuch:
PHP:
 <?php $root = "Food";
   // retrieve the left and right value of the $root node 
   $result = mysql_query('SELECT lft, rgt FROM tree '. 
                          'WHERE title="'.$root.'";', $dbconnect); 
   $row = mysql_fetch_array($result); 
   // start with an empty $right stack 
   $right = array(); 
   // now, retrieve all descendants of the $root node 
   $result = mysql_query('SELECT title, lft, rgt FROM tree '. 
                          'WHERE lft BETWEEN '.$row['lft'].' AND '. 
                          $row['rgt'].' ORDER BY lft ASC;', $dbconnect); 
   // display each row 
   while ($row = mysql_fetch_array($result)) { 
       // only check stack if there is one 
       if (count($right)>0) { 
           // check if we should remove a node from the stack 
           while ($right[count($right)-1]<$row['rgt']) { 
               array_pop($right); 
           } 
       } 
       // display indented node title 
       echo str_repeat(" &nbsp; ",count($right))."<option value=\"".$row['rgt']."\">".$row['title']."</option>"; 
       // add this node to the stack 
       $right[] = $row['rgt']; 
   } 
} 
 
?>
<form id="form1" name="form1" method="post" action="">
  <select name="select" size="5" multiple="multiple">
    <?php display_tree($root); ?>
  </select>
</form>

Mein Problem taucht hier auf:
PHP:
 echo str_repeat(" &nbsp; ",count($right))."<option value=\"".$row['rgt']."\">".$row
Ich möchte, dass in dem Select-Feld auch eine Baumstruktur angezeigt wird. Das versuche ich durch Einrücken mittels &nbsp;. Jetzt wird allerdins folgender Code erzeugt:
HTML:
<option value="20">Food</option> &nbsp; <option value="13">Fruit</option> &nbsp;  &nbsp; <option value="8">Red</option> &nbsp;  &nbsp;  &nbsp; <option value="5">Cherry</option> &nbsp;  &nbsp;  &nbsp; <option value="6">Strawberry</option> &nbsp;  &nbsp; <option value="12">Yellow</option> usw.
Korrekterweise müsste es aber so aussehen:
HTML:
<option value="20">&nbsp; Food</option>
aber ich weiß im Moment nicht, wo ich ansetzen soll.

Nun zu meiner zweiten Frage. Ich hatte ja eingangs erwähnt, dass ich versuche des Weiteren eine simple Navigation zu realisieren. Ich möchte, dass immer nur der Knoten, ohne Kinder ausgegeben wird. D.h. ich wähle die Hauptkategorie, und sehe beispielsweise zwei Unterkategorien, nicht aber die Unterkategorien dieser, sondern erst, wenn ich darauf klicke, also erneut eine Abfrage starte. Meine Frage ist nun, geht das, wenn ich in der DB nur eine id und die Spalte rgt und lft habe? Oder muss eine weitere Spalte, z.B. mit einer parent_id her, damit ich rekursiv abfragen kann? Vielen Danke für eure Hilfe.
 
Zurück