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.
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