365 votes

Comment configurer Sqlite3 pour qu'il soit insensible à la casse lors de la comparaison de chaînes de caractères ?

Je veux sélectionner des enregistrements dans une base de données sqlite3 par correspondance de chaîne. Mais si j'utilise '=' dans la clause where, j'ai découvert que sqlite3 est sensible à la casse. Quelqu'un peut-il me dire comment utiliser la comparaison de chaînes sans tenir compte de la casse ?

596voto

cheduardo Points 1929

Vous pouvez utiliser COLLATE NOCASE dans votre SELECT requête :

SELECT * FROM ... WHERE name = 'someone' COLLATE NOCASE

De plus, en SQLite, vous pouvez indiquer qu'une colonne doit être insensible à la casse lorsque vous créez la table en spécifiant collate nocase dans la définition de la colonne (les autres options sont binary (par défaut) et rtrim ; voir aquí ). Vous pouvez spécifier collate nocase lorsque vous créez un index. Par exemple :

create table Test
(
  Text\_Value  text collate nocase
);

insert into Test values ('A');
insert into Test values ('b');
insert into Test values ('C');

create index Test\_Text\_Value\_Index
  on Test (Text\_Value collate nocase);

Expressions impliquant Test.Text_Value devraient maintenant être insensibles à la casse. Par exemple :

sqlite> select Text\_Value from Test where Text\_Value = 'B';
Text\_Value      
----------------
b               

sqlite> select Text\_Value from Test order by Text\_Value;
Text\_Value      
----------------
A               
b               
C    

sqlite> select Text\_Value from Test order by Text\_Value desc;
Text\_Value      
----------------
C               
b               
A               

L'optimiseur peut aussi potentiellement utiliser l'index pour la recherche et la correspondance insensible à la casse sur la colonne. Vous pouvez le vérifier en utilisant la fonction explain Commande SQL, par exemple :

sqlite> explain select Text\_Value from Test where Text\_Value = 'b';
addr              opcode          p1          p2          p3                               
----------------  --------------  ----------  ----------  ---------------------------------
0                 Goto            0           16                                           
1                 Integer         0           0                                            
2                 OpenRead        1           3           keyinfo(1,NOCASE)                
3                 SetNumColumns   1           2                                            
4                 String8         0           0           b                                
5                 IsNull          -1          14                                           
6                 MakeRecord      1           0           a                                
7                 MemStore        0           0                                            
8                 MoveGe          1           14                                           
9                 MemLoad         0           0                                            
10                IdxGE           1           14          +                                
11                Column          1           0                                            
12                Callback        1           0                                            
13                Next            1           9                                            
14                Close           1           0                                            
15                Halt            0           0                                            
16                Transaction     0           0                                            
17                VerifyCookie    0           4                                            
18                Goto            0           1                                            
19                Noop            0           0

26 votes

Après avoir (re)créé la table avec 'COLLATE NOCASE', j'ai remarqué qu'elle était beaucoup plus rapide que la requête WHERE name = 'someone' COLLATE NOCASE. BEAUCOUP plus rapide (six à dix fois, en gros ?)

11 votes

Selon la documentation, l'ajout de COLLATE NOCASE à l'index n'est pas nécessaire si le champ lui-même a déjà cette collation définie : " La séquence d'assemblage par défaut est la séquence d'assemblage définie pour cette colonne dans l'instruction CREATE TABLE. "

36 votes

COLLATE NOCASE ne fonctionnera qu'avec du texte ASCII. Une fois que vous avez "FIANCÉ" ou "voilà" dans les valeurs de vos colonnes, il n'y aura pas de correspondance avec "fiancé" ou "VOILA". Après avoir activé l'extension ICU, LIKE devient insensible à la casse donc 'FIANCÉ' LIKE 'fiancé' est vrai, mais 'VOILA' LIKE 'voilà' est toujours fausse. Et ICU+LIKE a l'inconvénient de ne pas utiliser l'index, donc il peut être lent sur les grandes tables.

153voto

Craz Points 3664
SELECT * FROM ... WHERE name = 'someone' COLLATE NOCASE

6 votes

Si vous êtes comme moi et que vous voulez plus de documentation sur le collationnement, vous pouvez la trouver sur cette page : sqlite.org/datatype3.html Il suffit de faire défiler vers le bas jusqu'à #6.0

60voto

Nick Dandoulakis Points 26809

Vous pouvez le faire comme ça :

SELECT * FROM ... WHERE name LIKE 'someone'

(Ce n'est pas le site solution, mais dans certains cas, elle est très pratique)

" Le LIKE l'opérateur fait un motif de motifs. L'opérande de droite contient le motif, l'opérande l'opérande de gauche contient la chaîne à comparer avec le motif. A symbole de pourcentage ("%") dans le motif correspond à toute séquence de zéro ou plus caractères dans la chaîne. Un trait de soulignement ("_") dans le modèle correspond à tout caractère unique de la chaîne de caractères. Tout autre caractère correspond lui-même ou sa casse inférieure/supérieure équivalent (c'est-à-dire insensible à la casse correspondant) . (Un bug : SQLite ne comprend uniquement les majuscules/minuscules pour les caractères ASCII pour les caractères ASCII. L'opérateur LIKE est sensible à la casse pour les caractères unicode qui qui se trouvent au-delà de la plage ASCII. Pour Par exemple, l'expression 'a' LIKE 'A' est VRAIE mais est VRAIE, mais 'æ' LIKE 'Æ' est FAUX.)".

0 votes

@MM-BB oui, à moins que nous n'effectuions le LIKE sur une colonne qui est déclarée (ou indexée) comme COLLATE NOCASE, il y aura un balayage complet des lignes.

1 votes

Ce n'est pas un bug, c'est une limitation documentée. La même page citée dans la réponse mentionne l'extension ICU qui gère les caractères unicode. (Peut-être n'était-ce pas le cas en 2009)

1 votes

Cela produira des résultats inattendus si votre recherche contient %

46voto

oscarkuo Points 5849

Ce n'est pas spécifique à sqlite mais vous pouvez simplement faire

SELECT * FROM ... WHERE UPPER(name) = UPPER('someone')

0 votes

L'autre partie du problème de performance consiste à trouver les lignes correspondantes dans le tableau. SQLite3 supporte-t-il les index basés sur des fonctions ? Indexer la colonne ou l'expression de recherche (par exemple "UPPER(name)") dans une situation comme celle-ci est généralement une bonne idée.

17 votes

Attention, comme l'a suggéré Cheduardo, SQLite ne peut pas utiliser un index sur 'name' lors de l'exécution de cette requête. Le moteur de base de données devra analyser toutes les lignes, en convertissant tous les champs 'name' en majuscules et en effectuant la comparaison.

0 votes

Il s'agit uniquement de l'ASCII - quelque chose comme Jóga échouera

5voto

Dmitry Points 31

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X