• Jetzt anmelden. Es dauert nur 2 Minuten und ist kostenlos!

Suche in Liste aus mehrdimensionalen Arrays

Timmer

Mitglied
Hey, ich habe ein paar Arrays, in denen Daten stehen, wie Land, Bundesland, Regierungsbezirk und Landkreis. Alle diese Einträge haben eine ID, ein belongs_to zum Übergeordneten Eintrag und den Namen. Die Einträge sind in 4 Arrays gespeichert, jeweils Land, Bundesland (usw...). Wenn ich jetzt in der Suche einen Suchbegriff eingebe, wird onChange die Liste aktualisiert, alle Einträge, die auf den Suchbegriff passen, UND alle übergeordneten Elemente werden angezeigt. Das realisiere ich momentan mit einer while-Schleife:

PHP:
$all_regions = get_assoc_array($DBCONNECT, "SELECT region_id, belongs_to FROM region");
    
    $suchen = addslashes( trim( $IN['_suchen']));
    
    $results = dbquery($DBCONNECT, "SELECT region_id FROM region WHERE region_desc LIKE '%{$suchen}%'");
    
    while ( $rec = mysql_fetch_array($results)) {
      $lauf = 0;
      $found[] = $region_id = $rec['region_id'];
      $found[] = $belongs_to = $all_regions[$region_id];

      while ( $belongs_to > 0 && $lauf < 20) {
        $found[] = $belongs_to = $all_regions[$belongs_to];
        $lauf++;
      }

    }
    
    array_unique($found);

    if(count($found) == 0) $found[] = 'FALSE';
Wenn $belongs_to gleich 0 ist, liegt ein Land vor, also kein übergeordneter Eintrag mehr. Als Bremse einer Endlosschleife habe ich noch $lauf eingebaut.

In der Liste wird einfach nur geprüft, ob count($found) gleich 0 ist oder ob die ID des Eintrags in $found zu finden ist, wenn eines der beiden Statements TRUE ist, wird der Eintrag angezeigt.

Mein Problem: Ich möchte jetzt aber auch alle untergeordneten Einträge anzeigen lassen. Wenn ich also Bayern eingebe, sollen Regierungsbezirke wie Unterfranken und Städte wie Aschaffenburg angezeigt werden. Das ganze natürlich über die ID's und die Belong_to's. Mir fehlt nur ein Ansatz, wie ich das realisieren könnte...

Jemand eine Idee?

PS: Falls euch ein paar der oben genannten Funktionen nicht bekannt sein sollten, ich programmiere auf dem Firmen-PHP-Framework...
 
Zuletzt bearbeitet:
Wie sieht denn deine Datenbank genau aus? Wie gut kannst du denn mit MySQL umgehen? Das Ganze könnte man, denke ich, auch mit dem Query direkt lösen, falls du da noch nicht dran gedacht hast... Das würde dann auch Rechenleistung sparen, da du wahrscheinlich sehr viele Einträge hast, die "geholt" und überprüft werden müssen. :)
 
Ein rekursiver Query? Zeig mir da mal ein Beispiel...

Naja, Datenbanktabelle: region_id, belongs_to, region_desc, region_type, und ein paar Infos zum Ersteller und Updater. region_id ist die ID des Eintrags, belongs_to die ID des übergeordneten Eintrags, region_desc der Name und region_type ist der Typ des Eintrags (im Moment land als Land, state als Bundesland, admin_district als Regierungsbezirk und district als Landkreis). Das Problem ist, dass es nicht immer nur 4 Ebenen sind, das kann von Kunde zu Kunde variieren, manche haben 8 Ebenen, manche nur 2...

PS: Die Suchfunktion funktioniert schon, es werden alle übergeordneten Einträge des Suchbegriffs sowie alle untergeordneten Einträge der 2 unteren Ebenen angezeigt. Sucht man nach Land, werden also alle Einträge, die dem Land untergeordnet, bis auf die Landkreise... Ist aber 'quasi' hardcodet, ich will aber was dynamisches, was auch mit mehr als 4 Ebenen zurechtkommt...
 
Hm... Naja, was du jetzt als "rekursiven Query" bezeichnest, meine ich als
SELECT * FROM foo WHERE belongs_to = ( SELECT noch_was FROM bar WHERE id = 'foobar' )
Ich weiß nicht, inwiefern dir das weiterhilft... Das würde auch wieder bedeuten, dass man nur so viele Ebenen abklappern kann, wie man angibt, und da auch ausschließlich so viele. Nicht mehr, nicht weniger.

*grübel* Um's nochmal zusammen zu fassen, damit ich es eventuell besser verstehe... Daran scheiterts nämlich gerade bei mir. ;)
Du hast eine (große) Datenbank, in der verschiedene Länder stehen, die verschieden oft, je nach Kunde unterteilt werden. Du möchtest nun eine rekursive Suche, die vom Fund aus, bis zur obersten Ebene läuft?
Habe mir dazu mal eine Grafik erzeugt (per Hand), die mir beim Denken hilft. Jeder Untereintrag hat eine eigene ID und einen Verweis auf die ID des übergeordneten Eintrags.
Das heißt, dass du eigentlich einen Query benötigst, der dir den Fund rausgibt. Diesem Fund entnimmst du dann alle wichtigen Daten, unter anderem belongs_to. Dann schreibst du eine Funktion, die wieder einen Query formt, die als Parameter eben dieses belongs_to akzeptiert und den nächsten übergeordneten Eintrag sucht. Die oberste Ebene sollte dabei als belongs_to ein Kennzeichen haben, sowas wie 'null', den du dann abfragst (hast du ja schon).

Um meine Gedanken zu Papier zu bringen:
PHP:
function FindParent( $parentID, &$output ) {
  // Output wird referenziert, um die weiteren Funde hinzuzufügen.
  $result = dbquery( $DBCONNECT, "SELECT * FROM region WHERE belongs_to = '$parentID'" );
  if( $row = mysql_fetch_row( $result ) ) {
    $found[] = $row[ 'region_id' ];
    if( $row[ 'belongs_to' ] != 0 ) {
      FindParent( $row[ 'belongs_to' ] );
    }
  } else {
    $found[] = "Fehler! " . mysql_error( );
  }
}

$suchen = addslashes( trim( $IN[ "_suchen" ] ) );
$results = dbquery( $DBCONNECT, "SELECT * FROM region WHERE region_desc LIKE '%{$suchen}%'";

while( $row = mysql_fetch_array( $results ) ) {
  $found[] = $region_id = $row[ 'region_id' ];
  if( $row[ "belongs_to" ] != 0 ) {
    FindParent( $row[ 'belongs_to' ], $found );
  }
}

Ist das, so ungefähr das, was du suchst?

Mit freundlichen Grüßen,


DarkDragon1993
 
Nein, ich will nicht bis zur oberen Ebene, sondern bis zur Unteren...

Naja, der Unterschied liegt darin, dass ich 2 Arrays beziehe, einmal einen Array mit ALLEN Daten und belongs_to als Key, und einen Array mit den Suchergebnissen... Mit einem rekursiven Query mein ich ein Query mit einer Funktion, die sich selbst immer wieder aufruft, bis keine Daten mehr gefunden werden... Als Query wird das nicht zu bewerkstelligen sein, sondern nur als Funktion mit den Arrays...
 
Ja... Dann müsstest du im Query der Funktion eigentlich nur ein wenig umstellen. Anstelle der Funktion verwendest du dann diese:
PHP:
function FindChild( $ownID, &$output ) { 
  // Output wird referenziert, um die weiteren Funde hinzuzufügen. 
  $result = dbquery( $DBCONNECT, "SELECT * FROM region WHERE region_id = '$ownID'" );
  if( mysql_num_rows( $result ) === 0 ) {
    return; // Alles abgeklappert
  }
  while( $row = mysql_fetch_array( $result ) ) { 
    $found[] = $row[ 'region_id' ]; 
    if( $row[ 'belongs_to' ] != 0 ) { 
      FindChildren( $row[ 'belongs_to' ] ); 
    } 
  }
}


Oder du nutzt eben dein Array und klapperst das mehrmals von oben bis unten ab und durchsuchst deine Arrays. Allerdings würde ich diese Arrays zweidimensional aufbauen. Damit würde sich die Suche bestimmt erleichtern.
Anstatt $found[] = $region_id = $rec[ 'region_id' ]; würde ich $found[] = $rec; benutzen. Hilft dir DAS vielleicht? ^^
 
Zuletzt bearbeitet:
Gut, ich setze mich mit meinen Kollegen nochmal hin und versuch, eine Lösung für das Problem zu finden =)

Wenn es jemanden interessiert, würde ich hier die Lösung posten ^^
 
Naja, das ist dabei jetzt rausgekommen, ich habe die Strategie geändert: Ich speichere einmal den Pfad als Text (z.B. 'Deutschland|Bayern|Unterfranken|Aschaffenburg') und einmal den Pfad mit IDs (z.B. '40,2,53,54') in der Datenbank ab. Beim Erstellen der Liste suche ich bei der Suchfunktion den Suchbegriff einfach im Textpfad (alle untergeordneten Einträge werden gefunden und angezeigt), die gefundenen ID-Pfade explode ich und trage die IDs in den found[]-Array (der enthält alle gefundenen IDs).

Damit hab ich erreicht, was ich wollte.

Zur Berechnung der Pfade benutze ich folgendes Script:
PHP:
function berechne_region_pfad( $parent = 0, $region_step = 0, $region_desc_path = '', $region_id_path = '', $region_id = 0) {

  global $DBCONNECT, $IN;
    
  $sql = "SELECT * FROM region WHERE belongs_to = '$parent' ORDER BY region_desc";
  $sth = dbquery( $DBCONNECT, $sql);
  $region_desc_path_param = $region_desc_path;
  $region_id_path_param = $region_id_path;
  while ( $sth && ( $rec = dbfetch_record( $sth))) {
    $region_desc_path = $region_desc_path_param;
    if ( $region_desc_path > '') $region_desc_path .= '|';
    $region_desc_path .= $rec['region_desc'];

    $region_id_path = $region_id_path_param;
    if ( $region_id_path > '') $region_id_path .= ',';
    $region_id_path .= $rec['region_id'];
    
    $upd = "UPDATE region SET region_step = '$region_step', region_desc_path = '$region_desc_path', region_id_path = '$region_id_path'";
    $upd .= " WHERE region_id = '{$rec['region_id']}'";
    dbquery( $DBCONNECT, $upd);
    
    berechne_region_pfad( $rec['region_id'], $region_step+1, $region_desc_path, $region_id_path, $region_id);
  }
}
Zum Starten der Rechnerei genügt ein einfaches 'berechne_region_pfad();'

=)

[EDIT]

Und region_step habe ich auch eingeführt, damit wird die Ebene des Elementes berechnet. 0 ist oberste Ebene, 3 ist (in diesem Fall) die unterste Ebene.
 
Zuletzt bearbeitet:
Zurück
Oben