2009-12-03 4 views
1

Diverses incarnations de cette question ont été posées ici avant, mais j'ai pensé que je donnerais un autre coup de feu.mysql recherche par mot-clé sur plusieurs colonnes

J'avais une mauvaise configuration de base de données. Une seule entité (widget) a été divisé en deux tables:

CREATE TABLE widgets (widget_id int(10) NOT NULL auto_increment)

CREATE TABLE widget_data ( widget_id int(10), field ENUM('name','size','color','brand'), data TEXT)

ce fut moins cet idéal. Si je voulais trouver des widgets d'un nom, d'une couleur et d'une marque spécifiques, je devais faire une jointure à trois dans la table widget_data. donc je me suis converti au type de table raisonnable:

CREATE TABLE widgets (widget_id int(10) NOT NULL auto_increment, name VARCHAR(32),size INT(3),color VARCHAR(16), brand VARCHAR(32))

Cela rend la plupart des requêtes beaucoup mieux. Mais cela rend la recherche plus difficile. Il était l'habitude que si je voulais rechercher des widgets pour, disons, '% black%', je voudrais juste SELECT * FROM widget_data WHERE data LIKE '%black%'. Cela me donnerait toutes les instances de widgets qui sont de couleur noire, ou sont fabriqués par Blackwell Industries, ou autre. Je saurais même exactement quel champ correspond, et pourrait montrer cela à mon utilisateur. Comment puis-je effectuer une recherche similaire en utilisant la nouvelle disposition de table?

Je pourrais bien sûr faire WHERE name LIKE '%black%' OR size LIKE '%black%'... mais cela semble maladroit, et je ne sais toujours pas quels champs correspondent. Je pourrais lancer une requête séparée pour chaque colonne sur laquelle je veux correspondre, ce qui me donnerait toutes les correspondances et comment elles correspondaient, mais ce serait un coup de performance. des idées?

Répondre

3

Vous avez deux exigences contradictoires. Vous souhaitez effectuer une recherche comme si toutes vos données se trouvaient dans un seul champ, mais vous souhaitez également identifier le champ spécifique correspondant.

Il n'y a rien de mal avec votre expression WHERE name LIKE '%black%' OR size LIKE '%black%'.... C'est une recherche parfaitement valide sur la table telle que vous l'avez définie. Pourquoi ne pas simplement vérifier les résultats dans le code pour voir lequel correspondait? C'est un surcoût minimal.

Si vous voulez une syntaxe plus propre pour votre SQL, vous pouvez créer une vue sur la table, en ajoutant un champ supplémentaire qui consiste à concaténer les autres domaines:

CREATE VIEW extra_widget_data AS 
    SELECT (name, size, color, brand, 
      CONCAT(name, size, color, brand) as all_fields) 
    FROM widget_data; 

alors vous devez ajouter un index sur ce champ, ce qui nécessite plus d'espace, le temps CPU à maintenir, etc. Je ne pense pas que ça vaut le coup.

0

Vous voudrez sans doute vous intéresser à la fonction de recherche en texte intégral MySQL, ce qui vous permet de faire correspondre plusieurs colonnes de type varchar.

http://dev.mysql.com/doc/refman/5.1/en/fulltext-search.html

+1

La table en question est innodb et ne peut pas être changée en myisam, donc l'index de texte intégral n'est malheureusement pas une option –

+0

Les index de texte intégral peuvent être utilisés avec des tables InnoDB ou MyISAM et peuvent être créés uniquement pour CHAR, VARCHAR ou colonnes TEXT. –

2

Vous pouvez inclure une partie de WHERE expression dans les colonnes sélection. Par exemple:

SELECT 
    *, 
    (name LIKE '%black%') AS name_matched, 
    (size LIKE '%black%') AS size_matched 
FROM widget_data 
WHERE name LIKE '%black%' OR size LIKE '%black%'... 

vérifier alors la valeur de name_matched sur le côté du script.

Vous ne savez pas quel effet cela aura sur les performances. Feal libre de le tester avant d'aller en production

Questions connexes