the-FoX: Kategorien & SQL

Hallo und ein wuuunderschönen Guten Morgen ;-)

ich quäl mich schon das ganze Wochenende mit PHP und SQL rum :-(
und zwar versuche ich Objekte (Notizzettel) in Kategorien einzuordnen und bin zu folgenden zwei Tabellen gekommen:

Kategorie-Tabelle:

ID       - ID Der Kategorie
Titel    - Kategoriename
ParentID - ID der übergeordneten Kategorie (wenn Hauptkategorie, dann 0)

Notizzettel-Kategorie:

ID      - ID der Notiz
Titel   - Titel der Notiz
Text    - Der Notiztext
Cat-ID  - ID der Kategorie in der diese Notiz hängt

Mein konkretes Problem ist:
Wie stell ich am besten die Kategorie-Hirachie bei einer Notiz da ? Also statt nur Unterkategorie3 soll da stehen Kategorie/Unterkategorie2/Unterkategorie3

muss ich alles mit SELECT nach und nach von Unterkategorie3 aus nach oben durchforsten doer geht es eleganter?

Und wie bastel ich mir ein aufklappbares Menü ?

Kategorie1
  Unterkategorie2
  Unterkategorie3
    Unterunterkategorie1
    Unterunterkategorie2
      Unterunterunterkategorie1

Unterunterkategorie3
  Unterkategorie4
Kategorie2
Kategorie3

Das müsste doch mit einer Rekursiven Funktionmachbar sien oder ?!
Kann mir jemand weiter helfen ?!

Zudem würd ich gerne wenn ich in Kategorie1 bin alle 10 letzten Notizen der gesamten Unter- und UNterunterkategorien mit anzeigen ;-)
ich weiß, ich bin anspruchsvoll *smile*

Wär cool, wenn mir jemand weiter helfen könnte, vieleicht auch nen ganz anderer Ansatz !? Ich möchte abernicht festgelegt sein, was die tiefe der Kategorien angeht :-/

tausend Dank schon mal im Vorraus

the-FoX

  1. Hallo,

    Und wie bastel ich mir ein aufklappbares Menü ?

    Meinst Du ein Menue mit Java Script? Dafuer habe ich mal dieses Menue genommen: http://aktuell.de.selfhtml.org/artikel/dhtml/sitemap/index.htm

    Das müsste doch mit einer Rekursiven Funktionmachbar sien oder ?!

    Wenn Du das oben genannte Script nutzt musst Du lediglich die Eintraege in "function initArray()" dynamisch generieren. Damit meine ich Eintraege wie "Note(1,0,'Tutorials','')". Ist dort jedoch sehr gut dokumentiert.

    Ich glaube Du musst hierfuer die Datensaetze jedoch vorher sortieren lassen (ORDER BY ASC)...

    Soweit die erste Hilfe von mir

    -> Andreas

  2. Moin

    Hallo und ein wuuunderschönen Guten Morgen ;-)
    ich quäl mich schon das ganze Wochenende mit PHP und SQL rum :-(
    und zwar versuche ich Objekte (Notizzettel) in Kategorien einzuordnen und bin zu folgenden zwei Tabellen gekommen:

    Kategorie-Tabelle:
    ID       - ID Der Kategorie
    Titel    - Kategoriename
    ParentID - ID der übergeordneten Kategorie (wenn Hauptkategorie, dann 0)

    Notizzettel-Kategorie:
    ID      - ID der Notiz
    Titel   - Titel der Notiz
    Text    - Der Notiztext
    Cat-ID  - ID der Kategorie in der diese Notiz hängt

    Mein konkretes Problem ist:
    Wie stell ich am besten die Kategorie-Hirachie bei einer Notiz da ? Also statt nur Unterkategorie3 soll da stehen Kategorie/Unterkategorie2/Unterkategorie3

    Also, ich versuch mal ein längeres Beispiel anzugeben. Das basiert im Prinzip zu großen Teilen auf meinem Forumsskript, also wenn du dir das anschauen willst, findest du es unter http://www.ploetzli.ch/abi2001/forum.php?source=on.

    Mein Ansatz liest vor dem Verarbeiten einfach erstmal alle Daten aus der Datenbank aus und packt sie in ein schönes assoziatives Array. Solange du nicht Megabyteweise Kategorien angelegt hast, sollte das kein größeres Problem sein. Sollte das dich dann doch stören, kannst du bestenfalls noch eine zusätzliche Tabelle (oder auch Spalte) pflegen in der zu jeder Kategorie alle Überkategorien abgelegt sind (durch Kommas getrennt), so dass du dann später irgendetwas in der Art von:

    $result=mysql_query("SELECT ueberkategorien FROM kategorien WHERE ID = $kategorie");
    list($ueberkategorien)=mysql_fetch_row($result);
    $result=mysql_query("SELECT * FROM kategorien WHERE ID IN ($ueberkategorien)");

    für die Variante mit einer Kommaseparierten Liste aller Überkategorien machen kannst.

    muss ich alles mit SELECT nach und nach von Unterkategorie3 aus nach oben durchforsten doer geht es eleganter?

    s.o. Mir ist zumindest mit den von MySQL beherrschten Möglichkeiten nichts eleganteres bekannt. Achte aber auch darauf, dass du vorher gegebenenfalls die Tabelle lockst, damit nicht eine andere Instanz deines Skriptes zwischendurch Kategorien anlegt/löscht und das ganze in eine Endlosschleife steuert. Es ist eigentlich überhaupt eine gute Idee alle nötigen Datenbankabfrage durchzuführen, bevor die Verarbeitung oder gar Ausgabe beginnt.

    Und wie bastel ich mir ein aufklappbares Menü ?
    Kategorie1
      Unterkategorie2
      Unterkategorie3
        Unterunterkategorie1
        Unterunterkategorie2
          Unterunterunterkategorie1
        Unterunterkategorie3
      Unterkategorie4
    Kategorie2
    Kategorie3
    Das müsste doch mit einer Rekursiven Funktionmachbar sien oder ?!
    Kann mir jemand weiter helfen ?!

    Genau. Das sieht doch schon fast wie die Baumdarstellung eines Forums aus, und da kann ich mein Beispiel anbringen.

    Zunächst einmal lese ich alle Daten (zumindest alle Daten über Kategorien) aus der Datenbank aus und lege sie in einem assoziativen Array mit der Kategorie-ID als Schlüssel ab. Damit das nachher leichter wird, lege ich zu jeder Kategorie noch alle (direkten) Kindkategorien in einem Array ab, was später ein bisschen Aufwand erspart.

    $result=mysql_query("SELECT * FROM kategorien");
    while($tmp=mysql_fetch_array($result)) {
     $kategorien[ $tmp["ID"] ] =$tmp;                         // Alle Daten in das Array
     if($tmp["ID"]!=0)                                        // Wenn es keine Hauptkategorie ist, dann
      $kategorien[ $tmp["ParentID"] ]["kinder"][]=$tmp["ID"]; //  mache einen Eintrag in der Kinderliste der entsprechenden Überkategorie
    }

    So. Nun habe ich eigentlich alles was ich für eine rekursive Funktion brauche. Ich gehe das $kategorien-Array durch und für jede Hauptkategorie rufe ich die Funktion auf:

    foreach( $kategorien as $kategorie)
     if($kategorie["ParentID"]==0)
      MaleKategorie($kategorie["ID"]);

    function MaleKategorie($id)
    {
     global $kategorien;

    echo $kategorien[$id]["Titel"]."\n";                     // Zeile mit Info über die Kategorie ausgeben
     if(isArray($kategorien[$id]["kinder"]))                  // Wenn Kinder da sind
      foreach($kategorien[$id]["kinder"] as $kind)            // Alle Kinder durchgehen
       MaleKategorien($kind);                                 // und malen
    }

    Das sollte schonmal alle Einträge schön baumförmig ausgeben. Das zu formatieren (etwa mit Hilfe von <ul>) sollte nicht schwer sein. Gegebenenfalls muss die SQL-Abfrag noch um ein geeignetes ORDER BY ergänzt werden.

    Mit diesem Array sollte auch eine Ausgabe in der Form von Hauptkategorie/Unterkategorie/Unterunterkategorie nicht schwer sein.

    Zudem würd ich gerne wenn ich in Kategorie1 bin alle 10 letzten Notizen der gesamten Unter- und UNterunterkategorien mit anzeigen ;-)

    Ich weiss nicht ganz ob ich dich recht verstehe, aber ich versuch es einfach mal.
    Ich denke dass es dafür schon sinnvoll wäre für die Einträge jeder Kategorie eine extra Datenbankabfrage zu machen. Du könntest natürlich auch vorher alle Einträge in ein Array laden und dass dann durchgehen, aber das würde sich wohl nur lohnen wenn du auf einer Seite ohnehin alle Einträge oder einen Großteil davon darstellen willst. Ansonsten bietet sich an, den rekursiven Ansatz zu erweitern:

    function MaleKategorienMitNotizen($id)
    {
     global $kategorien;

    echo $kategorien[$id]["Titel"]."\n";        // Erstmal den Kategorietitel ausgeben
     $result=mysql_query("SELECT FROM notizzettel WHERE Cat-id = $id ORDER BY ID desc LIMIT 10");
     while($tmp=mysql_fetch_array($result)
      echo $tmp["Titel"]."\n";                   // die letzen 10 Notizen ausgeben, die neueste Notiz zuoberst
     foreach($kategorien[$id]["kinder"] as $kind)
      MaleKategorienMitNotizen($id);
    }

    Das zu formatieren sollte ebenso simpel sein wie oben. Zwei Punkte fallen auf: Ich habe hier Datenbankabfrage mitten in der Skriptausführung, die sollte man vielleicht an den Anfang des Skriptes verlagern. Wenn du vorher alles in ein Array schreibst lässt sich die Sortierung auch leichter umkehren. Außerdem basiert die Sortierung auf der ID. Je nach deinen Wünschen brauchst du vielleicht auch noch eine Zeit-Spalte nach der du dann sortieren kannst.

    Ich möchte abernicht festgelegt sein, was die tiefe der Kategorien angeht :-/

    Jo, das ist eine sehr gute Idee. Ich möchte hiermit nochmal allen Programmierern die Zero-One-Infinity Rule ans Herz legen, da das imho die eleganteste Form der Problemlösung ist: http://www.tuxedo.org/~esr/jargon/html/entry/Zero-One-Infinity-Rule.html.

    Disclaimer: Tippfehler entstehen nur durch die elektronische Übertragung und sind ungewollt. Aller Programmcode ist ungetestet. Das Finden von logischen oder syntaktischen Fehlern ist Aufgabe für den interessierten Leser. Wichtig: Diese Fragmente dienen dem Verständnis und enthalten daher keinerlei Code zur Validierung von Usereingaben.

    --
    Henryk Plötz
    Grüße aus Berlin

    1. tausend Dank!! ;-)
      Das werd ich die Tage mal checken. Die Idee mit einem Array klingt gut, zumal es wirklich nciht unendlich viele Einträge werden.
      FoX