Daniel: MySQL-Abfrage mit "Rekursion" möglich?

Moin!

Vielleicht kann mir hier jemand eine Antwort geben.
Folgendes Problem: Ich habe hier eine Datenbank wo in einer Tabelle folgenden Daten drin sind: ID, Name, Parent-ID.
Die Parent-ID verweist auf die jeweilige Eltern-ID in derselben Tabelle. Eine Abfrage soll jetzt alle Datensätze die mit einer bestimmten Eltern-ID verknüpft sind auflisten z.B. alle Datensätze die 1 als Parent-ID haben.
Jetzt kann das Ganze aber theoretisch unbegrenzt in die Tiefe gehen z.B. 6 hat Parent-ID 4, 4 hat Parent-ID 2 und 2 hat erst Parent-ID 1. Nun sollen aber auch die Datensätze mit ID 6 und 4 berücksichtigt werden und nicht nur der Datensatz mit ID 2.
Es müsste also eine Art Rekursion stattfinden. Ist so etwas mit MySQL überhaupt möglich oder kann ich das nur umsetzen mit Hilfe eines z.B. PHP-Skripts? Ich brauche so ein Anfrage für eine (wahrscheinlich) einmalige interne Sache, Performance ist also ziemlich egal.

Und bitte keine Antworten wie "Notfalls von Hand in die Einträge schauen". Die Datenbank hat mehrere 10.000 Einträge, da werde ich mit Sicherheit nicht alles einzeln durchforsten.

Gruß
Daniel

  1. mit JSP könntest du es folgendermaßen machen:

    • die StartID in einen Vector speichern
    • das folgende musst du so lange durchführen, bis sich die Größe des Vectors nicht mehr verändert:
    • für jeden Vector-Eintrag eine neue Abfrage durchführen und die Ergebnisse zum Vector hinzufügen, wenn sie noch nicht enthalten sind

    aber ich würde mir das genau überlegen, wenn du irgendwo einen falschen Eintrag hast, kommst du schnell in eine Endlosschleife

  2. mit den heutigen möglichkeiten liegt das bie mysql nicht drin.

    man kann aber die tabelle mit sich selbst 'join'en.

    z.b.:
    SELECT E.ElternID, P.ParentID
    FROM tabelle E join tabelle P
    ON E.ElternID = P.ParentID

    1. mit den heutigen möglichkeiten liegt das bie mysql nicht drin.

      Danke für die Antwort. Dann muss ich mir ein Skript basteln womit ich das mache. Habe eigentlich schon geahnt, dass das mit MySQL nicht drin ist. Wollte nur zur Sicherheit noch andere Meinungen dazu hören.

      Gruß
      Daniel

      1. Hello,

        Danke für die Antwort. Dann muss ich mir ein Skript basteln womit ich das mache. Habe eigentlich schon geahnt, dass das mit MySQL nicht drin ist. Wollte nur zur Sicherheit noch andere Meinungen dazu hören.

        Da füllst Du dann einfach ein Mehrdimensionales Array mit dem Level als Index. Das übergibst du der Funktion einfach immer wieder. Vergiss nicht einen Rekursionszähler ins Array einzubauen.

        Harzliche Grüße aus http://www.annerschbarrich.de

        Tom

        --
        Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
        Nur selber lernen macht schlau
  3. Hallo Daniel,

    Jetzt kann das Ganze aber theoretisch unbegrenzt in die Tiefe gehen z.B. 6 hat Parent-ID 4, 4 hat Parent-ID 2 und 2 hat erst Parent-ID 1. Nun sollen aber auch die Datensätze mit ID 6 und 4 berücksichtigt werden und nicht nur der Datensatz mit ID 2.

    Das ist schlecht, aber einfach zu realisieren :-)

    5 hat Parent-ID 3,
    3 hat Parent-ID 5

    Es müsste also eine Art Rekursion stattfinden. Ist so etwas mit MySQL überhaupt möglich oder kann ich das nur umsetzen mit Hilfe eines z.B. PHP-Skripts? Ich brauche so ein Anfrage für eine (wahrscheinlich) einmalige interne Sache, Performance ist also ziemlich egal.

    MySQL unterstützt keine Stored Procedures, also kannst Du das nicht in MySQL lösen. Du solltest es skriptgesteuert tun. Dabei unbedingt auf Vorkommen von Schleifen überprüfen.

    Freundliche Grüsse,

    Vinzenz

    1. Hello,

      5 hat Parent-ID 3,
      3 hat Parent-ID 5

      und Tschüss

      5 hat Parent-ID 3, Level 4
      3 hat Parent-ID 5, Level 3

      Wenn jetzt wieder 5 geholt wird, müsste der Level==2 lauten und nicht 4 und es gibt einen ErrorLog, jedenfalls bei mir... ;-)

      Harzliche Grüße aus http://www.annerschbarrich.de

      Tom

      --
      Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
      Nur selber lernen macht schlau
  4. Hello,

    ich habe die Frage auch mal gehabt. Leider geht es mit MySQL nicht in einem Statement. Der vorgeschlagene Self-Join hilf auch nur eine Stufe weiter.

    Ich habe also die Rekursion in meine API (PHP) gelegt. Zur Sicherheit, dass sich das System nicht bei fehlerhaften Daten totläuft, gibt es auch noch ein Level-Feld, dass die jeweilige Hierarchiestufe speichert. Wenn der Parent dann nich einen Level kleiner (=höher) hat, als das Child, dann liegt ein Fehler vor, und die Schleife bricht ab.

    Außerdem gibt es bei mir noch eine Konstante DB_MAX_RECURSION

    Außerdem kann man auf diese Weise auch verschiedene Familien in einer Tabelle speichern.

    Die Abfragen gehen eigentlich auch ganz schnell. Die mesiten beginnen derzeit auf Level 4 und müssen also vier Elternstufen liefern. Von der Last merke ich da noch nichts.

    Harzliche Grüße aus http://www.annerschbarrich.de

    Tom

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau
    1. ich habe die Frage auch mal gehabt. Leider geht es mit MySQL nicht in einem Statement. Der vorgeschlagene Self-Join hilf auch nur eine Stufe weiter.

      dies sollte keine lösung sein, sondern ein gedanklicher ansatz.
      man kann die join's natürlich auch noch weiter schachteln, und so eine größere tiefe erreichen, wobei in jeder schachtelung auch eine zusätzliche spalte z.b. schachtelung=3 generiert werden kann.
      um hierbei die tiefe zu kontrollieren, muß in der tabelle natürlich eine ebene enthalten sein.
      diese ebene kann nun auch in der on bedingung angewandt werden:
      on E.ebene < P.ebene

  5. yo,

    ich würde dir raten, rekursionen aus dem datenbank-design rauszunehmen. in der praxis wird es sicherlich oft benutzt, aber es sollte vermieden werden. rekursionen führen zu einigen problemen. eine zweite tabelle ist hier anzuraten, wo die id und die parent_id stehen.

    Ilja

    1. Hello,

      ich würde dir raten, rekursionen aus dem datenbank-design rauszunehmen. in der praxis wird es sicherlich oft benutzt, aber es sollte vermieden werden. rekursionen führen zu einigen problemen. eine zweite tabelle ist hier anzuraten, wo die id und die parent_id stehen.

      Und damit Du die dann nicht rekursiv abfragen musst, baust Du am besten eine dritte Tabelle, und damit Du die dann nicht rekursiv abfragen musst, baust Du am besten eine vierte Tabelle, und damit Du die dann nicht rekursiv abfragen musst, baust Du am besten eine fünfte Tabelle, und damit Du die dann nicht rekursiv abfragen musst, baust Du am besten eine sechste Tabelle, und damit Du die dann nicht rekursiv abfragen musst, baust Du am besten eine siebte Tabelle.

      Für den Anfang reichen sieben Ebenen. Und nun weißt Du ja, wie man[tm] es machen soll.

      Harzliche Grüße aus http://www.annerschbarrich.de

      Tom

      --
      Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
      Nur selber lernen macht schlau
      1. yp,

        wie gesagt, ich würde eine zusätzliche tabelle empfehlen, nicht mehrere.

        Ilja

  6. Hello,

    Wenn die Anzahl deiner Sätze pro Ebene begrenzbar ist, kommst Du sogar vollständig ohne Rekursion aus: mit gezielter Denormalisierung.

    Schlüsselfeld sehr lang

    0001.
    0001.0001.
    0001.0002.
    0001.0001.0001
    0001.0001.0001.0001
    0002.
    0002.0001.0001.
    0002.0001.0002.
    0002.0001.0003.
    0002.0002.0001.
    0002.0002.0002.

    usw.

    Ich denke, du siehst, wie die Begrenzug der Nummernkreise pro Ebene die Rekursion vermeiden hilft.

    Es lassen sich so sofort alle Eltern und Kinder _in_einem_Statement_ besorgen.

    Angenommen, Du hast das Child

    0001.0001.0001.0001

    und möchtest nun den kürzesten Weg zur Wurzel zurückverfolgen, dann muss der Wert in der Datenbank einfach immer mit dem entprechenden linken Teil der Child-ID übereinstimmen.

    Pseudeocode:

    select ID from $table where ID=left($child(length(trim((ID)));

    oder:

    select ID from $table where locate(trim(ID),$child)=1;

    Harzliche Grüße aus http://www.annerschbarrich.de

    Tom

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau