13 Stimmen

Anzeige aller Kinder jedes Elternteils

Ich habe eine Tabelle People . Ich möchte eine HTML-Tabelle anzeigen, die aus jedem übergeordneten Element besteht, mit allen darunter liegenden untergeordneten Elementen.

 _________
|People   |_____________________________________________
|-------------------------------------------------------|
| id     | parent | firstname     | lastname            |
|-------------------------------------------------------|
| 1        0        James           Donovan             |
| 2        0        Jeffrey         Williams            |
| 3        0        Emmit           Herring             |
| 4        2        Carol           Williams            |
| 5        2        Sarah           Williams            |
| 6        1        Nikolai         Donovan             | 
|_______________________________________________________|

Erwartetes Ergebnis:

 ________________________________________________
|Jeffrey Williams                                |
|------------------------------------------------|
|  - Carol Williams                              |
|  - Sarah Williams                              |
|________________________________________________|
|James Donovan                                   |
|------------------------------------------------|
|  - Nikolai Donovan                             |
|________________________________________________|
|Emmit Herring                                   |
|------------------------------------------------|
|________________________________________________|

Wie baue ich ein assoziatives Array, das die richtige Ergebnismenge enthält, um darüber zu iterieren? Ich bin verwirrt über das richtige SQL und das richtige PHP, um das endgültige Array zu erstellen.

Insbesondere bin ich unsicher, wie ich eine hierarchische Beziehung zwischen zwei MySQL-Tabellen anzeigen kann. Soweit ich weiß, sind SQL-Ergebnismengen nicht multidimensional. Das Einfügen einer SQL-Abfrage in eine for Schleife ist schrecklich für die Leistung. Was tun Sie also?

Ich schätze, dass ich nach einer Implementierung einer Adjazenzliste in MySQL suche.

Diese Frage sollte einfach sein, wenn ich alles in zwei Tabellen aufteilen könnte, aber leider muss ich bei dieser unüblichen Tabellenstruktur bleiben.

14voto

Ilmari Karonen Punkte 47398

Dazu gibt es mehrere Möglichkeiten:

1. Die naheliegendste Möglichkeit besteht darin, zunächst eine Liste aller Eltern abzurufen und dann in einer Schleife eine separate Abfrage für die Kinder der einzelnen Eltern durchzuführen. Sie sagen, dass dies "schrecklich für die Leistung" ist, aber es sollte wirklich nicht sein, vorausgesetzt, dass Sie einen Index auf die parent Spalte und dass sich Ihr MySQL-Server nicht auf der anderen Seite des Planeten befindet.


2. Wenn Sie dies wirklich in einer einzigen Abfrage tun wollen, können Sie eine LEFT JOIN auf dem Tisch gegen sich selbst:

SELECT
  p.id AS parent_id,
  p.firstname AS parent_firstname,
  p.lastname  AS parent_lastname,
  c.id AS child_id,
  c.firstname AS child_firstname,
  c.lastname  AS child_lastname
FROM
  People AS p
  LEFT JOIN People AS c ON c.parent = p.id
WHERE p.parent = 0
ORDER BY p.id

Noch einmal: Sie wirklich, wirklich benötigen einen Index für die parent Spalte. Die ORDER BY Klausel ist dazu da, um sicherzustellen, dass die Kinder jedes Elternteils zusammen sortiert werden; Sie können sie z. B. ändern in etwas wie p.lastname, p.firstname, p.id, c.lastname, c.firstname, c.id wenn Sie die Namen in alphabetischer Reihenfolge sortiert haben möchten. In PHP müssen Sie dann eine Schleife über die Ergebnisse ziehen und eine neue Kopfzeile ausgeben, wenn sich die übergeordnete ID ändert (und denken Sie daran, den Fall zu behandeln, dass die child_* Spalten sind NULL), etwas wie:

$res = mysql_query( $sql );
$last_parent_id = 0;
while ( $row = mysql_fetch_object( $res ) ) {
    if ( $row->parent_id != $last_parent_id ) {
        // print parent header
        $last_parent_id = $row->parent_id;
    }
    if ( $row->child_id ) {
        // print child row
    }
}

3. Die dritte Möglichkeit ist, alle Zeilen mit einer einfachen SELECT * FROM People abfragen und den Baum in PHP erstellen:

$res = mysql_query( "SELECT * FROM People" );  // add WHERE clauses if needed
$names = array();
$parents = array();
$children = array();

while ( $row = mysql_fetch_object( $res ) ) {
    $names[ $row->id ] = array( $row->firstname, $row->lastname );
    if ( $row->parent == 0 ) {
        $parents[] = $row->id;
    } else {
        if ( !array_key_exists( $row->parent, $children ) )
            $children[ $row->parent ] = array();
        $children[ $row->parent ][] = $row->id;
    }
}

foreach ( $parents as $parent_id ) {
    // print parent header
    if ( array_key_exists( $parent_id, $children ) ) {
        foreach ( $children[ $parent_id ] as $child_id ) {
            // print child row
        }
    }
}

Ps. Wenn Sie nicht wirklich zeigen wollen alle die Eltern und Kinder in der Tabelle, sondern nur diejenigen, die zu einer einzigen Familie gehören, dann sollten Sie trotzdem versuchen, die Filterung in SQL vorzunehmen, um nicht zu viele Datensätze abzurufen.

2voto

Federico Zancan Punkte 4768

Einem traditionellen Ansatz folgend, denke ich, dass es ein guter Ausgangspunkt sein könnte, mit SQL zu beginnen und Tabellen zu verbinden (auch wenn die linke Tabelle und die rechte Tabelle in diesem Fall die gleiche wäre).

Das liegt vor allem daran, dass man bei der Verwendung eines RDBMS immer mit tabellarischen Strukturen arbeiten muss, und dass das Verbinden von Tabellen auf diese Weise eine Garantie für die Datenkonsistenz darstellt.

Beginnen Sie also mit etwas wie:

SELECT 
       a.id parent_id, a.firstname parent_name, a.lastname parent_lastname, 
       b.id child_id, b.firstname child_firstname, b.lastname child_lastname
FROM 
       People a LEFT OUTER JOIN People b ON a.id = b.parent
WHERE  
       a.parent = 0;

Zweitens sollten Sie lieber eine "fetch_all"-Strategie verwenden (mit mysqli php-Erweiterung, zum Beispiel, aber es ist verfügbar mit PDO auch), was Ihnen die Möglichkeit gibt, mit einer einzigen Operation die gesamte Ergebnismenge in einem zweidimensionalen assoziativen Array abzurufen.

An diesem Punkt können Sie Ihren Weg wählen.

All-PHP: Sie können das Array mit PHP bearbeiten und direkt das Präsentationsmarkup erstellen, um die Daten nach Bedarf zu organisieren, echo den HTML-String an den Browser weiterleiten.

AJAX: Wenn - zum Beispiel - Ihr PHP-Skript eher über AJAX aufgerufen wurde, könnten Sie das Abfrageergebnis-Array auch durchlaufen, aber dieses Mal interpretieren, um eine JSON-Struktur aufzubauen, mit der Sie auf den Aufruf reagieren würden, einfach so:

{
    "1": {
        "id": 1,
        "firstname": "James",
        "lastname": "Donovan",
        "children": {
            "6": {
                "id": 6,
                "firstname": "Nikolai",
                "lastname": "Donovan"   
            }
        }
    },
    "2": {
        "id": 2,
        "firstname": "Jeffrey",
        "lastname": "Williams",
        "children": {
            "4": {
                "id": 4,
                "firstname": "Carol",
                "lastname": "Williams"  
            },
            "5": {
                "id": 5,
                "firstname": "Sarah",
                "lastname": "Williams"  
            }
        }
    },
    "3": {
        "id": 3,
        "firstname": "Emmit",
        "lastname": "Herring",
        "children": { }
    }
}

Eine solche Darstellung wäre für den Datenaustausch besser geeignet, da Ihr clientseitiges Javascript sie nahtlos erkennen und zum Auffüllen eines bereits vorhandenen leeren Tabellengerüsts verwenden könnte. Natürlich könnten Sie PHP haben, um json_encode() die Ergebnisse Array direkt statt Umstrukturierung es in etwas anderes wie dieses, aber Sie würden sich mit etwas, das nicht viel weiter als die solide Datensatz-ähnliche Array-Darstellung, die Sie bereits haben gehen würde finden.

Schließlich wäre die All-Mysql-Lösung, eine gespeicherte Prozedur vorzubereiten, die gezielt die Datenstruktur aufbaut, nach der Sie suchen, z. B. 1 Zeile pro Familie, mit dem vollständigen Namen der Eltern als erste Spalte und den vollständigen Namen der Kinder als nachfolgende Spalten (leere Felder, wenn die Person keine Kinder hat, wie Emmit Herring).

Sie könnten die Ergebnismenge wieder mit PHP "fetch_all" abrufen, das Array durchlaufen und wären fertig.

Wenn es also um die Leistung geht, sollte dieser letzte Ansatz die besten Ergebnisse garantieren, auch wenn man sagen muss, dass der Server dafür einen Preis in Form von Rechenlast und Speicherbelegung zahlt, wenn man mit großen Datenmengen zu tun hat.

1voto

Josh Punkte 12248

Sie könnten eine Schleife in einer Schleife verwenden:

$res = mysql_query("SELECT PARENT");
while( $row = mysql_fetch_assoc($res) )
{

  // echo parent

  $res2 = mysql_query("SELECT CHILD WHERE PARENT SOMETHING");
  while( $row2 = mysql_fetch_assoc($res2) )
  {

    // echo child
  }
}

Oder Sie heben sie für später auf und speichern eine Flagge.

$people = array();

$res = mysql_query("SELECT PARENT");
while( $row = mysql_fetch_assoc($res) )
{
  $people[] = array('is_parent' => true,
                    'info'      => $row);

  $res2 = mysql_query("SELECT CHILD WHERE PARENT SOMETHING");
  while( $row2 = mysql_fetch_assoc($res2) )
  {    
    $people[] = array('is_parent' => false,
                      'info'      => $row2);
  }
}

// later

foreach( $people as $person )
{
  if( $person['is_parent'] )
  {
    // echo parent
  }
  else
  {
    // echo child
  }
}

0voto

rvazquez Punkte 657

Warum nicht ein multilineares Array in JavaScript erstellen? Danach können Sie das Array einfach in einer Schleife durchlaufen, um die Ergebnisse im DOM zu erhalten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X