Comment puis-je effectuer une recherche (insensible à la casse) dans une colonne à l'aide du caractère générique LIKE?

289

J'ai regardé autour de moi et je n'ai pas trouvé ce que je cherchais, alors voilà.

SELECT * FROM trees WHERE trees.`title` LIKE  '%elm%'

Cela fonctionne bien, mais pas si l'arbre s'appelle Elm ou ELM etc ...

Comment rendre la casse SQL insensible à cette recherche générique?

J'utilise MySQL 5 et Apache.

David Morrow
la source
3
Si vous êtes tombé sur cette page mais que vos paramètres MySql fonctionnent sur cette requête pour Elm ou ELM et que vous VOULEZ qu'elle soit sensible à la casse, voir BINARYcomme ici: stackoverflow.com/questions/7857669/…
joshuahedlund
Cela ne dépend-il pas du classement des champs / tables? comme 'ut8_general_CI'
Yousha Aleayoub
Comment l'utiliser pour séquencer la requête de nœud?
Ashh
MySQL likedevrait être insensible à la casse par défaut.
Marko Bonaci

Réponses:

281
SELECT  *
FROM    trees
WHERE   trees.`title` COLLATE UTF8_GENERAL_CI LIKE '%elm%'

En fait, si vous ajoutez COLLATE UTF8_GENERAL_CIà la définition de votre colonne, vous pouvez simplement omettre toutes ces astuces: cela fonctionnera automatiquement.

ALTER TABLE trees 
 MODIFY COLUMN title VARCHAR(…) CHARACTER 
 SET UTF8 COLLATE UTF8_GENERAL_CI. 

Cela reconstruira également tous les index de cette colonne afin qu'ils puissent être utilisés pour les requêtes sans être précédés de '%'

Quassnoi
la source
34
En fait, si vous ajoutez COLLATE UTF8_GENERAL_CIà la définition de votre colonne, vous pouvez simplement omettre toutes ces astuces: cela fonctionnera automatiquement. ALTER TABLE trees MODIFY COLUMN title VARCHAR(…) CHARACTER SET UTF8 COLLATE UTF8_GENERAL_CI. Cela reconstruira également tous les index de cette colonne afin qu'ils puissent être utilisés pour les requêtes sans être précédés de '%'.
Quassnoi
1
ALTER TABLE trees MODIFY COLUMN title VARCHAR (…) cela semble le meilleur moyen, merci beaucoup ... laissez sql faire le travail
David Morrow
10
Rappel amical qu'il s'agit d'une réponse mysql. Si vous utilisez PostgreSQL, ILike est la solution à la question ci-dessus.
Steve
2
@RajanRawal: veuillez poster votre question en tant que question, pas en tant que commentaire. Merci.
Quassnoi
1
C'est la bonne réponse tant que votre assemblage d'origine était général, pas bin.
greenoldman
261

J'ai toujours résolu cela en utilisant plus bas:

SELECT * FROM trees WHERE LOWER( trees.title ) LIKE  '%elm%'
cwallenpoole
la source
47
et utilisation d'index de butin
Your Common Sense
3
MySQL 5 a-t-il un opérateur ILIKE?
Luke Maurer
27
mais pour la recherche %%, cela n'a pas d'importance de toute façon :)
Your Common Sense
5
@Col. - Certes, ce n'est pas idéal pour les colonnes indexées, mais cela fonctionnera pour une structure qui est déjà en place. J'ai également constaté que les recherches non sensibles à la casse sont plus souvent sur des colonnes qui ne sont pas indexées de toute façon.
cwallenpoole
1
Le classement par défaut est déjà CI. Donc, le vrai problème n'est pas dans cette question particulière. Mais c'est toujours une réponse parfaite de style SO.
Votre bon sens
48

La sensibilité à la casse est définie dans les paramètres de classement des colonnes / tables / bases de données. Vous pouvez effectuer la requête sous un classement spécifique de la manière suivante:

SELECT *
FROM trees
WHERE trees.`title` LIKE '%elm%' COLLATE utf8_general_ci

par exemple.

(Remplacez utf8_general_cipar le classement que vous jugez utile). Le _cisignifie insensible à la casse .

aioobe
la source
1
Dans MySQL 5.6, j'obtiens ERREUR 1273 (HY000): classement inconnu: 'utf_general_ci' . Je suppose que ce classement a été supprimé de MySQL? utf8_general_cifonctionne bien, cependant.
Mark Amery
1
Eu le même problème. Vous devez soit réparer votre problème, COLLATEsoit faire un tour simple comme celui-ci ( LOWER()vos deux chaînes avant la comparaison)
Menelaos Kotsollaris
Dans MySQL 5.6+ ou MariaDB 10+, il vous suffit de fournir l'instruction COLLATE avant votre état. Donc ça marche:SELECT * FROM products WHERE name COLLATE utf8_general_ci LIKE 'AB47TU';
stamster
41

Voici l'exemple d'une simple requête LIKE:

SELECT * FROM <table> WHERE <key> LIKE '%<searchpattern>%'

Maintenant, insensible à la casse en utilisant la fonction LOWER ():

SELECT * FROM <table> WHERE LOWER(<key>) LIKE LOWER('%<searchpattern>%')
Federico Piragua
la source
3
En fait, c'est une très bonne solution, surtout lorsque vous êtes confronté à des COLLATEproblèmes de format
Menelaos Kotsollaris
27

Utilisez simplement:

"SELECT * FROM `trees` WHERE LOWER(trees.`title`) LIKE  '%elm%'";

Ou utiliser

"SELECT * FROM `trees` WHERE LCASE(trees.`title`) LIKE  '%elm%'";

Les deux fonctions fonctionnent de la même façon

Vi8L
la source
15

Je fais quelque chose comme ça.

Obtenir les valeurs en minuscules et MySQL fait le reste

    $string = $_GET['string'];
    mysqli_query($con,"SELECT *
                       FROM table_name
                       WHERE LOWER(column_name)
                       LIKE LOWER('%$string%')");

Et pour MySQL PDO Alternative:

        $string = $_GET['string'];
        $q = "SELECT *
              FROM table_name
              WHERE LOWER(column_name)
              LIKE LOWER(?);";
        $query = $dbConnection->prepare($q);
        $query->bindValue(1, "%$string%", PDO::PARAM_STR);
        $query->execute();
Dave Doga Oz
la source
6

Je pense que cette requête fera une recherche insensible à la casse:

SELECT * FROM trees WHERE trees.`title` ILIKE '%elm%';
cgupta
la source
1
Je reçois une erreur de syntaxe sur mysql 5.5 lors de l'utilisation d'ILIKE dans mes requêtes
Steel Brain
18
Cela ne fonctionne que pour PostgreSQL; pas MySQL. postgresql.org/docs/current/static/functions-matching.html
Martin Tournoij
Comme indiqué précédemment, la question concernait MySQL et la réponse concerne PostgreSQL et bien sûr, l'enfer ne fonctionne pas avec MySQL. Je ne vote pas à la baisse mais je ne peux m'empêcher de me demander d'où viennent les votes
positifs
5

utilisation ILIKE

SELECT * FROM trees WHERE trees.`title` ILIKE '%elm%';

cela a fonctionné pour moi !!

ABS zarzis
la source
9
MySQL ne prend pas en charge ILIKE.
ttarchala
3
Cela fonctionne pour PostgreSQL, la question concernait MySQL.
Telmo Trooper
4

Vous n'avez besoin d' ALTERaucune table. Utilisez simplement les requêtes suivantes, avant la SELECTrequête réelle que vous souhaitez utiliser le caractère générique:

    set names `utf8`;
    SET COLLATION_CONNECTION=utf8_general_ci;
    SET CHARACTER_SET_CLIENT=utf8;
    SET CHARACTER_SET_RESULTS=utf8;
Lopofsky
la source
2
Ceci est un commentaire très sous-estimé. Il aborde la question de manière plus générale. Je pense que la syntaxe alter table est également importante, car la question peut vouloir que la comparaison soit limitée à cette seule colonne.
Brian Chrisman
1

bien dans mysql 5.5, comme l'opérateur est insensible ... donc si votre valle est elm ou ELM ou Elm ou eLM ou tout autre, et que vous utilisez comme '% elm%', il listera toutes les valeurs correspondantes.

Je ne peux pas dire sur les versions antérieures de mysql.

Si vous allez dans Oracle, comme le travail en respectant la casse, donc si vous tapez comme '% elm%', il n'ira que pour cela et ignorera les majuscules.

Étrange, mais c'est comme ça :)

user21546
la source
Ce n'est pas tout à fait vrai. Cela ne fonctionne de cette façon que si le classement est défini sur *_ci, ce qui signifie «insensible à la casse». Comme cela se trouve être par défaut pour tous les jeux de caractères pris en charge (problème show character set;pour vérifier cela) - la réponse est partiellement vraie :-) Seule la raison est incorrecte. Ce n'est pas l'opérateur qui est insensible à la casse, c'est le classement par défaut qui l'est.
silverdr
oui je suis d'accord avec vous. Cela dépend du caractère et toujours si vous êtes en production avec le caractère * _ci, alors la seule option est d'utiliser la clause binaire avant where
user21546
1
SELECT name 
       FROM gallery 
       WHERE CONVERT(name USING utf8) LIKE _utf8 '%$q%' 
       GROUP BY name COLLATE utf8_general_ci LIMIT 5 
user4189641
la source
galerie est le nom de la table, le nom est la colonne du tableau,
user4189641
2
veuillez ajouter une explication de votre code montrant ce qu'il fait et comment il aide - cela aidera les autres à l'avenir
Our Man in Bananas
0

Vous devez configurer le codage et le classement appropriés pour vos tables.

Le codage de la table doit refléter le codage réel des données. Quel est l'encodage de vos données?

Pour voir le codage de table, vous pouvez exécuter une requête SHOW CREATE TABLE tablename

Votre bon sens
la source
0

Lorsque je souhaite développer des recherches de casse insensibles, je convertis toujours chaque chaîne en minuscules avant de faire une comparaison

Rbacarin
la source
0

Vous pouvez utiliser la méthode suivante

 private function generateStringCondition($value = '',$field = '', $operator = '', $regex = '', $wildcardStart = '', $wildcardEnd = ''){
        if($value != ''){
            $where = " $field $regex '$wildcardStart".strtolower($value)."$wildcardEnd' ";

            $searchArray = explode(' ', $value);

            if(sizeof($searchArray) > 1){

                foreach ($searchArray as $key=>$value){
                    $where .="$operator $field $regex '$wildcardStart".strtolower($value)."$wildcardEnd'";
                }

            }

        }else{
            $where = '';
        }
        return $where;
    }

utilisez cette méthode comme ci-dessous

   $where =  $this->generateStringCondition($yourSearchString,  'LOWER(columnName)','or', 'like',  '%', '%');
  $sql = "select * from table $where";
roi néo
la source