2010-12-03 2 views
2

Grundsätzlich habe ich eine Datenbank voller Tabellen, und ich möchte sie alle durchlaufen, bis ich ein Ergebnis finde, das meiner Suchanfrage entspricht. Gibt es eine Möglichkeit, dies zu tun? Oder zumindest einen Befehl, um alle Tabellennamen zurückzugeben, damit ich sie durchlaufen kann, bis ich den richtigen Wert gefunden habe?Gibt es eine Möglichkeit, alle Tabellen in einer MySQL-Datenbank zu durchsuchen?

danke!

+1

Ich vermute, das leicht mit dynamischem SQL getan werden könnte. Fragen Sie eine Metatabelle ab, die alle Tabellennamen und Spaltennamen enthält, durchlaufen Sie dann diese Ergebnismenge und fragen Sie die Tabellen und Spalten nach Ihren Wünschen ab. Ich schreibe nicht als Antwort, weil ich nicht sicher bin, ob dies in MySQL machbar ist (ich weiß, dass ähnliche Tricks in Oracle funktionieren) – FrustratedWithFormsDesigner

Antwort

3

Aaah, Suchmaschinen. Spannendes Thema, aber ich würde eher etwas mit interner Intelligenz bauen als mit Brute-Force-Lösung. Ja - das Überprüfen jeder Tabelle/Spalte in der Datenbank ist brutal und kann zu Trägheit und falschen positiven Ergebnissen führen.

Lassen Sie mich Ihnen etwas präsentieren, das ich stattdessen verwenden würde. Bei der folgenden Lösung muss jede scannende Tabelle/Spalte manuell hinzugefügt werden, aber alles andere ist automatisch. Hier ist die Nutzung:

$e = new SearchEngine(); 
$e->addTable('users', 'id', 'login'); // table, primary key name, column to be searched in 
$e->addTable('users', 'id', 'last_name'); 
$e->addTable('towns', 'id', 'name'); 

print_r($e->search('austin')); // we search for exact match for word "austin" 

Und hier ist, wie es durchgeführt wurde:

class SearchEngine { 

    protected $tables = array(); 

    public function addTable($table, $key, $column) { 
     $this->tables[] = array(
      'table' => $table, 
      'key' => $key, 
      'column' => $column 
     ); 
    } 

    public function search($term) { 
     $q = array(); 
     foreach ($this->tables as $t) { 
      list($table, $key, $column) = $t; 
      $q[] = " 
       SELECT 
        $key AS searched_key, 
        '$key' AS searched_key_name, 
        '$table' AS searched_table, 
        '$column' AS searched_column, 
        $column AS searched_value 
       FROM $table 
       WHERE $column = $term 
      "; 
     } 
     $sql = implode(' UNION ', $q); 
     // query the database 
     // return results 
    } 

} // class SearchEngine 

Lassen Sie uns Beispielausgabe analysieren:

searched_key | searched_key_name | searched_table | searched_column | searched_value 
-------------+-------------------+----------------+-----------------+--------------- 
     276 |    id | users   | login   | austin 
     1782 |    id | users   | last_name  | austin 
      71 |    id | towns   | name   | austin 

Aus der obigen Tabelle, dass Begriff „austin“ herausfinden können, wurde in Tabelle users, Spalte login (Primärschlüssel 276) und Spalte last_name (Primärschlüssel 1782) gefunden.Es wurde auch in der Tabelle towns in der Spalte name (Primärschlüssel 71) gefunden;

Dieses Suchergebnis kann für Sie ausreichend sein. Oder können Sie die Liste weiter verarbeiten, die von jedem Tisch voller Zeile auszuwählen:

$out = array(); 
foreach ($rows as $row) { 
    $sql = " 
     SELECT * FROM {$row['searched_table']} 
     WHERE {$row['searched_key_name']} = {$row['searched_key']} 
     LIMIT 1 
    "; 
    // query the database 
    // append result to $out array 
} 
return $out; 

diese Weise werden Sie mit vollem Suchergebnis am Ende (im Gegensatz zu Zwischenergebnissen aus vorheriger Tabelle):

id: 276, login: austin, last_name: Powers, email: [email protected] 
id: 1782, login: michael, last_name: austin, email: [email protected] 
id: 71, name: austin, state: texas, country: usa 

Da die aktuelle Implementierung auf einen festen Vergleichsoperator beschränkt ist (WHERE-Feld = Wert), möchten Sie hier vielleicht etwas Flexibilität einführen. Wenn ja, muss Suchoperator an externe Klasse und injiziert in search() Funktion delegiert werden:

public function search(SearchOperator $operator, $term) { 
... 

Dann SearchOperator Bedürfnisse berücksichtigt werden, durch Ersetzen WHERE-Bedingung mit dem unten:

WHERE {$operator->toSQL($column, $term)} 

Nun lasst uns Fokus auf SearchOperator Implementierung. Da die Operatorimplementierung nur eine Methode bereitstellt, nämlich toSQL, benötigen wir keine vollständige Klasse oder sogar abstrakte Klasse. Schnittstelle wird in diesem Fall genügen:

interface SearchOperator { 

    public function toSQL($column, $term); 

} // interface SearchOperator 

Und lassen Sie uns einige Implementierungen definieren = darstellt (gleich) und LIKE Operatoren:

class Equals implements SearchOperator { 

    public function toSQL($column, $term) { 
     return "$column = '$term'"; 
    } 

} // class Equals 

class Like implements SearchOperator { 

    public function toSQL($column, $term) { 
     return "$column LIKE '$term'"; 
    } 

} // class Like 

natürlich jede andere Implementierung ist möglich - man denke etwa Klassen genannt Starts, EndsWith oder DoesNotContain.

Siehe aktualisierte Lösung Nutzung:

$e = new SearchEngine(); 
$e->addTable('users', 'id', 'login'); 
$e->addTable('users', 'id', 'last_name'); 
$e->addTable('towns', 'id', 'name'); 

print_r($e->search(new Like(), 'austin%')); // here we search for columns being LIKE 'austin%' 

Zeit einige abschließende Bemerkungen zu verlassen:

  • Above Beispiele unvollständig sind. Der Datenbankabfragecode wurde aus Gründen der Übersichtlichkeit weggelassen.
  • In den Beispielen verwendete SQL-Anweisungen bereinigen Eingabedaten nicht. Ich fordere Sie dringend auf, vorbereitete Anweisungen mit gebundenen Parametern zu verwenden, um ein großes Sicherheitsrisiko zu vermeiden.
  • Suchalgorithmus oben ist ein naives. Einige Optimierungen können durchgeführt werden (d. H. Gruppieren von Abfragen, die sich auf dieselbe Tabelle beziehen). Aber optimieren Sie nicht vorzeitig - warten Sie, bis es ein echtes Problem wird.

In der Hoffnung, das war hilfreich.

1

Sehr schlechte Idee. Allerdings sollten Sie müssen all tables suchen (und Sie verwenden MySQL) können Sie eine Liste bekommen mit:

SHOW TABLES; 

Und dann Schleife durch jede und (vorausgesetzt, Sie die Spalten kennen) abfragen sie.

+0

Darf ich fragen, warum das eine schlechte Idee ist? Ist es nur ressourcenintensiv? Die gesamte Datenbank enthält weniger als 2000 Zeilen, also ist sie relativ klein. – Parker

0

Wie andere bereits gesagt haben, ist es möglich, alle Tabellennamen und deren Spaltennamen aus dem Metadatenverzeichnis zu extrahieren. Sehen Sie sich die Datenbank "information_schema" an. Sie können eine Liste von Tabellen abrufen, über die Sie dann iterieren können.

Aber die Wahrscheinlichkeit ist, dass Sie die Datenbank falsch verwenden. Wir fragen die Datenbank nicht ab, wir fragen das Datenmodell ab. Das Datenmodell ist als eine Reihe von Tabellen/Ansichten usw. implementiert.

Können Sie uns einen Hintergrund geben, warum Sie dies tun müssen? Vielleicht gibt es bessere Alternativen?

0

Sie können in Ihrer Datenbank alle Tabellen erhalten mit

SHOW TABLES; 

Dann können Sie eine Schleife durch die Tabellen und die Struktur für jede Tabelle herauszufinden, mit

DISPLAY table_name; 

Aber Sie würden immer noch brauchen habe eine vage Idee, wie man die Spalten jeder Tabelle abfragt, um etwas zu finden. Also, es sei denn, Sie haben ein spezialisierteres Problem, z. Da alle Tabellen die gleiche bekannte Struktur haben, würde ich dem Gefühl zustimmen, dass Sie die Datenbank möglicherweise falsch verwenden und es könnte einen besseren Weg geben.

Verwandte Themen