Mysql
 sql >> Base de données >  >> RDS >> Mysql

Tout sélectionner où le champ contient une chaîne séparée par une virgule

Avec MySQL, vous pouvez utiliser FIND_IN_SET() :

SELECT * FROM mytable WHERE FIND_IN_SET('ios ', tags) > 0;

http://dev.mysql .com/doc/refman/5.0/en/string-functions.html#function_find-in-set

Notez que FIND_IN_SET s'attend à ce que les chaînes soient virgule séparés, pas virgule et espace séparé. Vous pourriez donc avoir des problèmes avec la dernière balise. La meilleure façon serait de normaliser la table; sinon vous risquez de supprimer les espaces des tags colonne; enfin vous pouvez contourner le problème en ajoutant un espace aux tags colonne :

SELECT * FROM mytable WHERE FIND_IN_SET('ios ', CONCAT(tags,' ')) > 0;

Si le nombre de balises est limité, vous pouvez envisager de convertir la colonne en un SET . Cela améliorera grandement l'efficacité.

MISE À JOUR

Sauf que j'ai mauvais les espaces . Ils sont avant les cordes et non après.

Donc :

SELECT * FROM mytable WHERE FIND_IN_SET(' ios', CONCAT(' ', tags)) > 0;

Mais encore une fois, débarrassez-vous de ces espaces - ils ne sont que des ennuis :-)

MISE À JOUR 2

Ce qui précède fonctionne, d'accord. Mais c'est presque tout ce que vous pouvez dire en ma faveur. Non seulement la solution est assez * in * efficace, mais elle rend également le système presque impossible à maintenir (j'y suis allé, j'ai fait ça, j'ai eu le T-shirt et un cul mâché en dessous). Je vais donc maintenant insister un peu en faveur de la normalisation, c'est-à-dire avoir au moins ces deux tables supplémentaires :

CREATE TABLE tags ( id      INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
                    tagName varchar(32) // I'm a bit of a cheapskate
);
CREATE TABLE has_tag ( tableid INTEGER, tagid INTEGER );

Combien est-ce mieux? Laissez-moi compter les chemins.

  • vous pouvez facilement ajouter des requêtes plus flexibles ("a toutes les balises dans iOS, C++, ..." ou "a au moins trois balises parmi celles-ci :( iOS, Python, SQL, .NET, Haskell)". Oui, vous pouvez le faire avec FIND_IN_SET , mais croyez-moi, vous ne l'apprécierez pas .
  • vous avez un dictionnaire contrôlé de balises, ce qui vous permet de vérifier si une balise est connue (ainsi que de générer facilement des listes telles que des listes déroulantes, ou -- quelqu'un a-t-il dit "jQuery Autocomplete" ?).
  • économise de l'espace disque (les balises sont écrites une seule fois)
  • les recherches sont rapides . Si vous connaissez déjà les balises que vous recherchez et que vous les pré-compilez en identifiants de balises, elles laisseront des marques de brûlure en caoutchouc SQL sur le trottoir lors de l'exécution (recherche indexée d'un entier évaluer!). Et les balises qui ne compileront pas ne seront pas là , et vous le saurez avant même que la recherche ne commence.
  • rend beaucoup plus facile de renommer les balises
  • peut contenir n'importe quel nombre de balises (vous risquez d'avoir une balise tronquée à 'iOS Developm' tôt ou tard...)

Je crois que le "champ CSV" est cens(ou)é parmi les SQL Antipatterns ( http://pragprog.com/book/bksqla/sql-antipatterns ), et pour cause.