Frage

Ich bin mit einem decicion im Umgang mit Gewinden Kommentare in unserem Projekt konfrontiert ... Ich habe eine einfache MySQL-Tabelle, die alle Kommentare hält. Es gibt zwei Arten: Eltern und Childs. repräsentieren Childs eine Antwort auf einen Elternteil oder ein anderes Kind.

Mein Problem:

-Comment (Tiefe 0)
- Antwort Child (Tiefe 1)
--- Antworten zum vorherigen Kind (Tiefe 2)
-Comment (Tiefe 0)

Stellen Sie sich die obige Struktur und eine MySQL-Abfrage mit LIMIT 2. der letzten Antwort schneiden würde (Tiefe 2). Eigentlich würde Ich mag, wie etwas sagen: Versuchen Sie, 2 zu begrenzen, wenn das Kind bis zum nächsten Elternteil gehen auf der linken Seite. Versuchte mehrere Anfragen ohne Glück ...

Was ich jetzt habe, ist wie folgt:
    WÄHLEN     SQL_CALC_FOUND_ROWS         *     VON         Bemerkungen     WO         comment_post_id = '{$ _REQUEST [ "ID"]}'     SORTIEREN NACH         comment_id, comment_date     DESC LIMIT 10"

Die wichtigen Tabellenfelder sind:
comment_id (Index) | comment_parent_id (enthält comment_id von Eltern oder NULL) | comment_date

Ich würde für alle Ideen sehr dankbar !!!

Saludos, Booosh

War es hilfreich?

Lösung

MySQL hat keine Funktionen baumartige Strukturen zu analysieren. Im einfachsten Fall (Kind eine ID des Mutter hat), müssen Sie programmatisch in den Baum rekursiv alle Unterknoten eines bestimmten Knotens zu lokalisieren. MaxLevel zeigt die Tiefe, zu der Sie gehen möchten. Es dekrementiert mit jedem rekursiven Aufruf, so dass Sie am Ende mit 0 enden, der Rekursion stoppt.

z. (Pseudo-Code)

findNodes(String parentId, int maxLevel)
{
  select * from posts where parent = parentId
  foreach (result...)
  {
    if (maxLevel > 0) 
    {
      findNodes(result.nodeId, maxLevel - 1)
    }
    doSomethingWIthAResult
  }
}

Um dies in einer prägnanten Art und Weise zu tun, gibt es eine Reihe von Techniken, von denen alle eine Art von Indexfeld beinhaltet, den Pfad zum aktuellen Beitrag enthält. TopNode: Der Weg könnte in etwa so aussehen Child1: Child2: Child3 ..., in dem Sie eine Auswahl wie dies tun könnten Select * from Beiträge in dem Pfad wie "TopNode%" und Tiefe = 2.

Andere Tipps

Denken Sie immer an der Frage, die Sie wirklich um die Datenbank fragen wollen und und übersetzen, dass in SQL - in diesem Fall, dass Sie „wollen eine Liste aller Top-Level-Kommentare mit ihren unmittelbaren Kindern, wenn überhaupt “.

zB. (Vereinfacht)

SELECT * FROM comments c1
LEFT JOIN comments c2 ON c2.parent_comment_id=c1.comment_id
WHERE c1.parent_comment_id IS NULL
ORDER BY c1.comment_date, c1.comment_id, c2.comment_date, c2.comment_id;

Mit diesem Ergebnis können Sie sie in der richtigen Reihenfolge aufschreiben - wenn c2.comment_id null ist, ist es ein Top-Level-Kommentar ohne Kinder, und wenn c1.comment_id wiederholt wird, dann ist es ein anderes Kind gleichen Kommentars.

Ich war mit dem gleichen Problem konfrontiert, nur ein, ich werde nur Tiefe tief.

--Comment (depth: 0)
---Reply  (depth: 1)

ich es geschafft, eine einzelne Abfrage zu verwenden, um alle diese Datensätze zu wählen, während die Top-Level-Comment Datensätze nur 10 begrenzt wird.

SELECT c.* FROM comments AS c WHERE c.OwnerId = 1 AND c.ParentId = 0 LIMIT 10
UNION
SELECT cc.* FROM comments AS cc
    INNER JOIN
    (
        SELECT CommentId FROM comments WHERE OwnerId = 1 AND ParentId = 0 LIMIT 10
    )
    AS c2
    ON cc.ParentId = c2.CommentId

Diese Abfrage im Grunde führt Folgendes aus:

  • Ruft die ersten 10 Datensätze, die Top-Level-Kommentare sind, und haben ein spezifische Eigentümer-ID.
  • Ruft alle Kommentare, die eine Eltern-ID gleich der Kommentar-ID haben, die von der ersten Abfrage und Gewerkschaften sie auf die Ergebnismenge zurückgegeben wurde.

Während ich denke, diese Abfrage effizienter wäre als für jeden Datensatz mehrere Anrufe auf die Datenbank zu machen, es macht immer noch den Fehler, die es zweimal die erste Abfrage ausgeführt wird. Einmal vor der Vereinigung, und ein in der Verbindung auf der Union.

Es scheint ziemlich schnell zu sein, aber nicht so schnell, wie ich möchte. Allerdings, wenn Ihre Datenbank entfernt ist, und die Latenzzeit ist ein Problem, diese Lösung dazu dienen könnte, besser als mehrere Remote-Abfragen an die Datenbank zu machen.

Ich schaffte es schließlich basierend auf Greg Adamskis Hinweis ... also nicht meine Antwort stimmen, aber überprüfe seine one !!!

Um das Problem kurz zu beschreiben ... Wir brauchen eine Paginierung für eine Kommentarliste auf unserer Website. Mit Hilfe eines Standard-Grenze dazu führen könnten, dass einige Kommentare würde nie ... Was gezeigt werden, mussten wir war eine Grenze, die nur unsere Eltern betroffenen Knoten nicht die cild Knoten, die Antworten sind ... eine lange Geschichte ... aber vielleicht einmal diese iis nützlich für jemanden:

    function getComments($comment_parent_id, $scope,&$comments, $db)
    {
        $res = $db->select("SELECT * FROM comments WHERE comment_post_id = '{$_REQUEST["ID"]}' AND comment_parent_id = '{$comment_parent_id}' ORDER BY comment_date DESC LIMIT {$scope}");

        while ($row = mysql_fetch_array($res, MYSQL_ASSOC)) 
        {
            $i = count($comments)+1;

            foreach ($row as $k => $v) {
                $comments[$i][$k] = $v;
            }

            //LOOK FOR REPLIES (childs of parent)
            if (mysql_num_rows($db->select("SELECT * FROM comments WHERE comment_parent_id = '{$row['comment_id']}' LIMIT 1")) != 0 ){
                getComments($row['comment_id'],100,$comments,$db);
            }
        }
    }

    //ARGUMENTS: parent_id (always starting with zero), scope, array holding comments, db class
    getComments(0,5,$comments,$db);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top