Anna: MySQL - Forum mit Antworten auf Antworten - Nur wie???

Hallo zusammen!

Bevor ich anfange: Falls ich nicht die richtigen Wörter benutze, bitte ich das zu entschuldigen, aber es kommt ja eigentlich nur auf's Verständnis an.
Und wenn das jetzt alles ein bisschen schwammig klingt, liegt das daran, daß ich unfähig bin es besser zu beschreiben. Das tut mir Leid. Ich hoffe ihr versteht es trotzdem.

Ich versuch's mal ganz einfach zu erklären.

Ich hätte gerne ein Forum mit folgenden Funktionen:
   - Man kann ein neues Thema eröffnen
   - Man kann Antworten auf bereits offene Themen geben
   - Man kann auf bereits gegebene Antworten nochmal antworten

Im Prinzip sollte es ein Forum sein wie hier.
Mit so einer Art Verzeichnis-Baum-Struktur.

Und aussehen sollte es ungefähr so:

------------

Thema 1:
   - Anwort 1
   - Anwort 2
      -Anwort 2.1
      -Anwort 2.2
      -Anwort 2.3
         -Anwort 2.3.1
   - Anwort 3
   - Anwort 4
   - Anwort 5

Thema 2:
   - Anwort 1
   - Anwort 2
   ...
------------

Mir kommt es besonders darauf an, daß man Antworten auf Anworten geben kann. Also wie zB "Antwort 2.1", die sich eben nicht mehr direkt auf das Thema bezieht, sondern auf "Antwort 2".

Mein Problem ist, ich versteh nicht so richtig, wie ich das umsetzen kann.
Mir fehlt ein Denkanstoß, oder wahlweise auch mehr Gehirn.

Ich hab mir das bis jetzt ungefähr so gedacht. Ich hab eine Tabelle mit:
   - einer id für jeden einzelnen Eintrag (sowohl Antworten als auch
     neue Themen)
   - Themen-id (um die einzelnen Einträge auch den jeweiligen Themen
     zuzuordnen)
   - Datum
   - Autor
   - Überschrift
   - Text

So weit so gut!
Jetzt kann man die Einträge einfach nach der Themen-id und dem Datum geordnet raussuchen.

Für die Antworten auf Antworten dachte ich mir, könnte ich noch eine zweite Tabelle nehmen, die
   - die id des Eintrags speichert (auf den sich die Anwort bezieht
     zB "Antwort 2")
   - und die id der Antwort darauf (zB "Antwort 2.1").
Das müßte man ja auch nur in den Fällen speichern, wenn es wirklich eine Antwort gibt.

Die Probleme:
   - Jetzt kann man nicht mehr nach dem Datum ordnen, weil "Antwort 2.1" ja
     auch zeitlich erst nach "Antwort 3" gespeichert worden sein könnte.
   - Zuerst 10 Beiträge raussuchen und dann für jeden in der zweiten
     Tabelle nachsehen, ob es Antworten darauf gibt, kommt mir auch nicht
     sehr klug vor.
   - Außerdem könnten unter den 10 zuerst rausgesuchten Beiträgen, ja auch
     schon Antorten auf Antworten sein, dann müßte man dafür erst wieder
     die übergeordneten Antworten raussuchen.
   - Dazu kommt noch, daß es vielleicht auf die Antworten der Antworten
     wieder Antworten gibt wie zB "Antwort 2.3.1".

Das kommt mir jetzt ein bisschen wie diese vielen "Wer-kennt-wen-über-wen"-Seiten vor. Die verstehe ich übrigens auch nicht. Ich glaub das wär der Schlüssel zu diesem Problem, oder anders rum. :-)

Das sieht jetzt sehr verwirrend aus! Ich hoffe ihr seid beim Lesen nicht verrückt geworden und versteht vielleicht ein bisschen was ich meine!
Ich möchte mich trotzdem für dieses Chaos entschuldigen!!!
Und vielen Dank für jeden, der bis hier hin durchgehalten hat!
:-)

Liebe Grüße
Anna

  1. Hi,

    Ich hab mir das bis jetzt ungefähr so gedacht. Ich hab eine Tabelle mit:
       - einer id für jeden einzelnen Eintrag (sowohl Antworten als auch
         neue Themen)

    Der Eröffnungsbeitrag eines neuen Themas kann durchaus als "Antwort" betrachtet werden - zu der es lediglich keine "Frage" bzw. vorhergehende Antwort, auf die sie sich bezieht, gibt.

    - Themen-id (um die einzelnen Einträge auch den jeweiligen Themen
         zuzuordnen)

    Für die Antworten auf Antworten dachte ich mir, könnte ich noch eine zweite Tabelle nehmen

    Das braucht keine zweite Tabelle. Eine zusäztliche Spalte mit einer parent-ID reicht aus. Da wird jeweils die ID der Antwort eingetragen, auf die sich diese Antwort bezieht. Das Eröffungsposting und Antworten, die sich nicht auf andere Antworten beziehen (so letzteres als Feature gewünscht wird), bekommen in dem Feld eine 0, eine -1 oder auch NULL.

    Die Probleme:
       - Jetzt kann man nicht mehr nach dem Datum ordnen, weil "Antwort 2.1" ja
         auch zeitlich erst nach "Antwort 3" gespeichert worden sein könnte.

    Das ist weniger ein Problem der Abspeicherung der Daten, als generell eines des gewählten Systems.
    Ob du alle Antworten chronologisch auflisten willst, oder in einerm Baumstruktur - das musst du entscheiden.

    - Dazu kommt noch, daß es vielleicht auf die Antworten der Antworten

    wieder Antworten gibt wie zB "Antwort 2.3.1".

    Das  macht nichts.
    Antwort "2.3" hat einen Integerwert als ID, und die wird bei Antwort "2.3.1" wiederum als parent-ID abgelegt.

    MfG ChrisB

    --
    Light travels faster than sound - that's why most people appear bright until you hear them speak.
    1. hi,

      Antwort "2.3" hat einen Integerwert als ID,

      Das interessiert mich, wie rechnest Du das um?

      Hotte

      --
      Wenn der Kommentar nicht zum Code passt, kann auch der Code falsch sein.
      1. Hi hotti!

        Antwort "2.3" hat einen Integerwert als ID,
        Das interessiert mich, wie rechnest Du das um?

        Wie was wo umrechnen?

        Jede Antwort hat eine ID.
        Elternknoten werden einfach über die ParentIDs identifiziert, wobei jede Antwort genau einen Elternknoten hat.

        Die Generierung von hierarchischen Zahl-Punkt-IDs erfolgt on the fly oder über eine berechnete Spalte, hat aber keinen Einfluss auf die Arbeit mit den Threadbäumen.

        MfG H☼psel

        --
        "It's amazing I won. I was running against peace, prosperity, and incumbency."
        George W. Bush speaking to Swedish Prime Minister unaware a live television camera was still rolling, June 14, 2001
        Selfcode: ie:% fl:( br:> va:) ls:& fo:) rl:? n4:& ss:| de:] js:| ch:? sh:( mo:) zu:)
        1. hi,

          »» > Antwort "2.3" hat einen Integerwert als ID,
          »» Das interessiert mich, wie rechnest Du das um?
          Wie was wo umrechnen?

          Naja, so wie IP nach einem vorgegebenen Schema, da haben wir jedoch nur
          0.0.0.0 bis 255.255.255.255

          wobei jeder Adresse like 2.3.1.5 ein Integer zugeordnet werden kann. Aber da sind die Grenzen:
          Alles zsammen 32 Bit, 255 Threads und 255 Antworten aber nur 3 Antworten auf Antworten überhaupt, wenn ich das so mache (nicht möglich: 255.255.255.255.1).

          Daher meine Frage.

          Hotte

          --
          Wenn der Kommentar nicht zum Code passt, kann auch der Code falsch sein.
          1. Hi hotti!

            Daher meine Frage.

            Got it!
            Die Generierung der hierarchischen IDs ist ein normale Tiefensuche oder Stringverknüpfung.

            Wobei ich aus Performancegründen die letzte Möglichkeit wählen würde. Die Position einer Antwort (oder genauer: eines Teilthreadbaums) wird sich schließlich nicht mehr ändern.

            MfG H☼psel

            --
            "It's amazing I won. I was running against peace, prosperity, and incumbency."
            George W. Bush speaking to Swedish Prime Minister unaware a live television camera was still rolling, June 14, 2001
            Selfcode: ie:% fl:( br:> va:) ls:& fo:) rl:? n4:& ss:| de:] js:| ch:? sh:( mo:) zu:)
            1. hi,

              Die Generierung der hierarchischen IDs ist ein normale Tiefensuche oder Stringverknüpfung.

              Ja, schon klar mein Lieber ;-)

              Ich hatte halt ebend nur son Gedankenblitz, das Prinzip der Umrechnung von IP-Adressen nach numerisch u.u. da rein zu bringen und irgendwie zu nutzen.

              Btw., Matthew Wright hat in seinem Forum auch diese Art der Zuordnung genutzt, mit "," statt "." (1 1,1 2 2,1 2,2 2,1,1 usw).

              Andererseits ist eine 32-Bit-Zahl schon ziemlich groß, soviele Messages wirds in einem Forum insgesamt kaum geben.

              Hotte

              --
              Count Down started..........................................................
              1. Hallo,

                also so wie ich das jetzt verstanden habe, benutze ich eine Tiefensuche, um an meine 10 Einträge, inklusive Antworten zu kommen, indem ich bei der ersten Antwort ("Antwort 1") anfange und mich dann durch alle Unter-Antworten durcharbeite.
                Und falls keine mehr vorhanden sind gehe ich zur nächsten Antwort ("Antwort 2") über.
                Bis ich insgesamt 10 Einträge zusammen habe.

                Und die Parent-ID speichere ich wie eine IP Adresse mit den Punkten dazwischen, oder haben wir das inzwischen wieder verworfen???
                Und was war mit dem Problem, daß es dann nur 3 Unter-Antworten geben kann, wegen zuweniger Punkte?

                Falls das bei den nested sets steht, tut es mir Leid, ich bin immernoch nicht ganz durch.
                Der Artikel scheint aber genau der richtige zu sein:
                http://www.klempert.de/nested_sets/#kap3

                mfg
                Anna

                1. Also tausend Dank an alle!

                  Ich glaub ich bin jetzt ein bisschen klüger geworden. Und hab auf alle Fälle viel Neues zu lesen. Da werd ich mich erstmal durcharbeiten und ein bisschen rumprobieren.

                  Wenn's danach dann an der Query-Umsetzung scheitert, meld ich mich einfach nochmal. :-)

                  Bis dann
                  Liebe Grüße
                  Anna

          2. Hello,

            Naja, so wie IP nach einem vorgegebenen Schema, da haben wir jedoch nur
            0.0.0.0 bis 255.255.255.255

            wobei jeder Adresse like 2.3.1.5 ein Integer zugeordnet werden kann. Aber da sind die Grenzen:
            Alles zsammen 32 Bit, 255 Threads und 255 Antworten aber nur 3 Antworten auf Antworten überhaupt, wenn ich das so mache (nicht möglich: 255.255.255.255.1).

            Das Problem dieser Lösung ist die leichte Sortierbarkeit des Index.
            Um die Sortierbarkeit herzustellen, muss man ein Format einführen.
            Das Format wiederum begrenzt den Nummernkreis jeder Ebene, also die Anzahl der möglichen Antworten auf den Teilthread.

            Wenn man die Diskussionen hier verfolgt, sieht man, dass diese manchmal ganz schön lang und auch verschachtelt werden können.

            Eine "Macke" dieses Forums ist mMn, dass man immer geneigt ist, Antworten auf das eigentliche Anliegen auf die letzte Antwort zu geben, statt auf das Anliegen.

            also...

            f----------
                  a1------------
                      a2------------
                          a3------------

            anstelle von

            f----------
                  a1------------
                  a2------------
                  a3------------

            was mMn aber daran liegt, dass das hier anders herum sortiert wird

            f----------
                  a3------------
                  a2------------
                  a1------------

            Wenn man nun binär codieren würde, wäre die "gepunktete Lösung" sicherlich leichter möglich, dann natürlich ohne die Punkte.

            Wenn Du mit 256 Antworten in jeder Ebene und einer maximalen Einrückung, die der Länge des Schlüssels entspricht, auskommst, ist das sicherlich die schnellere Lösung gegenüber den nested Sets.

            Manchmal liegt die Lösung in der Beschränkung einer Anwendung. Das hat Billy the Gator reich gemacht. Man kann sie dann bei Wachstum nämlich mehrfach (in verschiedenen Größen) verkaufen.

            Liebe Grüße aus dem schönen Oberharz

            Tom vom Berg

            --
            Nur selber lernen macht schlau
            http://bergpost.annerschbarrich.de
    2. echo $begrüßung;

      Eine zusäztliche Spalte mit einer parent-ID reicht aus.

      Nicht unbedingt, denn dann müsste man recht häufig rekursive Abfragen an die Tabelle richten, wenn man Teilbereiche eines Baumes haben möchte. Eine komfortablere Lösung für das Abfragen sind Nested Sets. Die kommen aber mit dem Preis von mindestens zwei zusätzlichen Feldern und einem erhöhten Aufwand beim Einfügen neuer Datensätze daher. (Zum Stichwort Nested Sets bekommt man mir einer "handelsüblichen" Suchmaschine genügend Lesematerial für den Anfang.)

      echo "$verabschiedung $name";

      1. Eine komfortablere Lösung für das Abfragen sind Nested Sets. Die kommen aber mit dem Preis von mindestens zwei zusätzlichen Feldern und einem erhöhten Aufwand beim Einfügen neuer Datensätze daher.

        Auch beim Löschen ;-)
        Dafür sind sie schnell. Und als ich den Threadtitel hier las, dachte ich sofort, dass Nested Sets die einzig logische Antwort sein sollten...

    3. Antwort "2.3" hat einen Integerwert als ID, und die wird bei Antwort "2.3.1" wiederum als parent-ID abgelegt.

      Ok, also speichere ich einfach für jeden Eintrag eine Parent-ID, die mir dann anzeigt, worauf sich diese Antwort bezieht.

      Und was schlagt ihr als Typ vor? INT oder VARCHAR wegen den Punkten?
      Man könnte natürlich die Punkte einfach weglassen.
      Also anstelle von 2.3.1 könnte man 231 speichern.
      Aber das geht auch nicht, weil das spätestens bei Antwort 11 zu Problemen führt. Die unterscheidet sich ja dann nicht mehr von Antwort 1 auf Antwort 1.

      ------------
      Thema 1 (Parent-ID: 0):
         - Anwort 1 (Parent-ID: 0)
         - Anwort 2 (Parent-ID: 0)
            -Anwort 2.1 (Parent-ID: 2)
            -Anwort 2.2 (Parent-ID: 2)
            -Anwort 2.3 (Parent-ID: 2)
               -Anwort 2.3.1 (Parent-ID: 2.3)
         - Anwort 3 (Parent-ID: 0)
         - Anwort 4 (Parent-ID: 0)
         - Anwort 5 (Parent-ID: 0)

      Thema 2 (Parent-ID: 0):
         - Anwort 1 (Parent-ID: 0)
         - Anwort 2 (Parent-ID: 0)
         ...
      ------------

      Ich dachte zuerst kurz daran, daß es vielleicht Probleme macht, wenn alle "Themen-Anfänge" (also: "Thema 1" und "Thema 2") und die direkt darauf folgenden Antworten alle als Parent-ID 0 haben. Aber die einzelnen Themen unterscheiden sich ja auch noch anhand der Themen-ID.
      Und die Reihenfolge der Antworten mit der gleichen Parent-ID kann man ja über das Datum ordnen.

      Aber da bleibt natürlich immernoch die Frage, wie man das in ein MySQL Query verwandeln kann. Unabhängig davon, wie es jetzt gespeichert wird.

      Sagen wir mal, ich will die 10 neuesten Einträge von einem bestimmten Thema anzeigen, aber mit den dazugehörigen Antworten.

      Ich kann ja nicht erstmal alle mit Parent-ID 0 raussuchen und dann einzeln nachfragen, oder es Parent-IDs gibt, die sich darauf beziehen.

      Ich les mal das über nested sets, vielleicht finde ich da was...

      1. Hi,

        Ok, also speichere ich einfach für jeden Eintrag eine Parent-ID, die mir dann anzeigt, worauf sich diese Antwort bezieht.

        Und was schlagt ihr als Typ vor? INT oder VARCHAR wegen den Punkten?

        Die Parent-ID enthält keine Punkte.

        Man könnte natürlich die Punkte einfach weglassen.
        Also anstelle von 2.3.1 könnte man 231 speichern.

        Nein. Das ist nicht die ID des Vorgängers, das sind gleich die mehrerer Vorgänger auf einmal.

        Ich dachte zuerst kurz daran, daß es vielleicht Probleme macht, wenn alle "Themen-Anfänge" (also: "Thema 1" und "Thema 2") und die direkt darauf folgenden Antworten alle als Parent-ID 0 haben.

        Noch mal: Ein "Themen-Anfang" ist bereits eine (Art von) "Antwort".
        Also erhält die erste Antwort, die *darauf* erfolgt, natürlich die ID dieses Themen-Anfangs als parent-ID.

        Aber da bleibt natürlich immernoch die Frage, wie man das in ein MySQL Query verwandeln kann. Unabhängig davon, wie es jetzt gespeichert wird.

        Das Stichwort Nested Sets hast du bereits.
        Das unterscheidet sich davon in so fern, dass es nicht nur in die Eltern-Richtung, sondern auch in die Kinder-Richtung die Beziehung abbildet.

        MfG ChrisB

        --
        Light travels faster than sound - that's why most people appear bright until you hear them speak.
        1. Hallo!

          »» Man könnte natürlich die Punkte einfach weglassen.
          »» Also anstelle von 2.3.1 könnte man 231 speichern.

          Nein. Das ist nicht die ID des Vorgängers, das sind gleich die mehrerer Vorgänger auf einmal.

          Verstehe. Das war dumm von mir.
          ...nein Moment. Ich glaub ich hab's immernoch nicht verstanden.

          Die Parent-ID enthält keine Punkte.

          Die Antwort 2.3.1 bezieht sich doch auf die Antwort 2.3 deshalb ist ihre Parent-ID auch 2.3

          ------------
          Thema 1 (Parent-ID: 0):
             - Anwort 1 (Parent-ID: 0)
             - Anwort 2 (Parent-ID: 0)
                -Anwort 2.1 (Parent-ID: 2)
                -Anwort 2.2 (Parent-ID: 2)
                -Anwort 2.3 (Parent-ID: 2)
                   -Anwort 2.3.1 (Parent-ID: 2.3)
             - Anwort 3 (Parent-ID: 0)
             - Anwort 4 (Parent-ID: 0)
             - Anwort 5 (Parent-ID: 0)

          Thema 2 (Parent-ID: 0):
             - Anwort 1 (Parent-ID: 0)
             - Anwort 2 (Parent-ID: 0)
             ...
          ------------

          Noch mal: Ein "Themen-Anfang" ist bereits eine (Art von) "Antwort".
          Also erhält die erste Antwort, die *darauf* erfolgt, natürlich die ID dieses Themen-Anfangs als parent-ID.

          Das hab ich verstanden, denk ich. Deshalb hat die "Anwort 1" zB auch Parent-ID 0
          genau wie alle anderen Antworten, die sich direkt darauf beziehen (Anwort 1 bis 5).

          Und alle Antworten, die sich auf "Antwort 2" beziehen haben Parent-ID 2
          Wie zB auch "Antwort 2.3".
          Und deshalb muß doch "Antwort 2.3.1" die sich auf "Antwort 2.3" bezieht auch Parent-ID 2.3 haben.
          Daher kommt der Punkt.

          Oder wie würde dafür die richtige Parent-ID lauten?

          Vielleicht steht's ja schon bei den nested sets und ich bin nur noch nicht an der richtigen Stelle angekommen.

          Danke schon mal!
          Anna

          1. Hi,

            Die Antwort 2.3.1 bezieht sich doch auf die Antwort 2.3 deshalb ist ihre Parent-ID auch 2.3

            Nein.
            2.3 ist keine ID.

            Jeder Datensatz hat eine eigene ID - einen Integerwert.
            Und zusätzlich eine Spalte, in der ggf. die ID seines unmittelbaren Vorfahren drin steht.

            MfG ChrisB

            --
            Light travels faster than sound - that's why most people appear bright until you hear them speak.
            1. Hi,

              Jeder Datensatz hat eine eigene ID - einen Integerwert.
              Und zusätzlich eine Spalte, in der ggf. die ID seines unmittelbaren Vorfahren drin steht.

              Achso!!!
              Jetzt versteh ich Dich!
              Jeder Eintrag in der Tabelle hat seine eigene ID, egal ob Neues Thema (So ne Art Antwort), oder echte Antwort, oder Antwort auf Antwort, etc.
              Und als Parent-ID dient die ID des Eintrags auf den sich die Antwort bezieht.

              Das klingt jetzt in der Erklärung eigentlich genauso, wie's Du's mir schon die ganze Zeit erklärt hast.
              Sorry! Ich stand wohl etwas auf dem Schlauch! :-)

              Ich zeichne es trotzdem nochmal auf, nur um sicher zu gehen:

              ------------

              Thema 1: (ID:1,Parent-ID:0)
                 - Anwort 1 (ID:2,Parent-ID:1)
                 - Anwort 2 (ID:3,Parent-ID:1)
                    -Anwort 2.1 (ID:4,Parent-ID:3)
                    -Anwort 2.2 (ID:5,Parent-ID:3)
                    -Anwort 2.3 (ID:12,Parent-ID:3)
                       -Anwort 2.3.1 (ID:13,Parent-ID:12)
                 - Anwort 3 (ID:6,Parent-ID:1)
                 - Anwort 4 (ID:7,Parent-ID:1)
                 - Anwort 5 (ID:11,Parent-ID:1)

              Thema 2: (ID:8,Parent-ID:0)
                 - Anwort 1 (ID:9,Parent-ID:8)
                 - Anwort 2 (ID:10,Parent-ID:8)
                 ...
              ------------

              Oh, bin ich ein Dödel!!!
              Tut mir Leid!
              Manchmal dauert's eben ein bisschen länger! :-)

              mfg
              Anna

  2. hi,

    eine solche Hierarchie ist schon ganz gut. Jeder Thread beginnt mit einer Zahl, die ggf. von einem Punkt gefolgt ist (falls Antworten da sind).

    Zum Sortieren nach Datum reicht es ja schon, das Datum vom Thread zu nehmen, was sich auf die Eröffnung eines Solchen bezieht.

    Innerhalb eines Threads kann die Sortierung nach Datum entfallen, Du musst Dich nur um die Einrückungen kümmern, so dass jede Antwort auf eine Antwort eingerückt ist. Das hab ich z.B. mit einer Rekursion gelöst wobei es auch bessere Lösungen gibt (google mal nach "nested set"), meine Rekusionsfunktion baut da eine Liste auf mit den üblichen Tags ul und li.

    Gespeichert hab ich das in einer Tabelle mit 1, 1.1, 2, 2.1, 2.2 usw. als Key.

    Hotte