Como definir o Sqlite3 para não fazer distinção entre maiúsculas e minúsculas ao comparar strings?

305

Quero selecionar registros do banco de dados sqlite3 por correspondência de string. Mas se eu usar '=' na cláusula where, descobri que o sqlite3 faz distinção entre maiúsculas e minúsculas. Alguém pode me dizer como usar string comparando maiúsculas e minúsculas?

quantidade
fonte

Respostas:

493

Você pode usar COLLATE NOCASEem sua SELECTconsulta:

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

Além disso, no SQLite, você pode indicar que uma coluna não diferencia maiúsculas de minúsculas ao criar a tabela, especificando collate nocasena definição da coluna (as outras opções são binary(o padrão) e rtrim; veja aqui ). Você também pode especificar collate nocasequando criar um índice. Por exemplo:

criar tabela Teste
(
  Text_Value texto agrupar nocase
);

insira nos valores de teste ('A');
insira nos valores de teste ('b');
inserir nos valores de teste ('C');

criar índice Test_Text_Value_Index
  em teste (Text_Value agrupa nocase);

Expressões envolvendo Test.Text_Valueagora não diferenciam maiúsculas de minúsculas. Por exemplo:

sqlite> selecione Text_Value em Test, em que Text_Value = 'B';
Text_Value      
----------------
b               

sqlite> selecione Text_Value na ordem de teste por Text_Value;
Text_Value      
----------------
UMA               
b               
C    

sqlite> selecione Text_Value na ordem de teste por Text_Value desc;
Text_Value      
----------------
C               
b               
UMA               

O otimizador também pode potencialmente usar o índice para pesquisa e correspondência que não diferenciam maiúsculas de minúsculas na coluna. Você pode verificar isso usando o explaincomando SQL, por exemplo:

sqlite> explica selecione Text_Value em Test, em que Text_Value = 'b';
addr opcode p1 p2 p3                               
---------------- -------------- ---------- ---------- ---------------------------------
0 Saltar 0 16                                           
1 Inteiro 0 0                                            
2 OpenRead 1 3 keyinfo (1, NOCASE)                
3 SetNumColumns 1 2                                            
4 Cordas8 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 Coluna 1 0                                            
12 Retorno de chamada 1 0                                            
13 Próximo 1 9                                            
14 Fechar 1 0                                            
15 Parada 0 0                                            
16 Transação 0 0                                            
17 VerifyCookie 0 4                                            
18 Saltar 0 1                                            
19 Noop 0 0                                            
cheduardo
fonte
20
Após (re) criar a tabela com 'COLLATE NOCASE', notei que era muito mais rápido que a consulta WHERE name = 'someone' COLLATE NOCASE. Muito mais rápido (seis a 10 vezes, aproximadamente?)
DefenestrationDay
10
De acordo com a documentação, acrescentando COLLATE NOCASEque o índice não é necessário se o próprio campo já tem este agrupamento definido: " O padrão seqüência de agrupamento é a seqüência de intercalação definida para essa coluna na instrução CREATE TABLE. "
Heinzi
29
COLLATE NOCASEfuncionará apenas com texto ASCII. Uma vez que você tenha "FIANCÉ" ou "voilà" nos valores da coluna, ele não corresponderá a "noivo" ou "VOILA". Depois de ativar a extensão da UTI, LIKEtorna-se sem distinção entre maiúsculas e minúsculas , então 'FIANCÉ' LIKE 'fiancé'é verdade, mas 'VOILA' LIKE 'voilà'ainda é falsa. E o ICU + LIKE tem a desvantagem de não usar o índice, por isso pode ser lento em grandes tabelas.
selecione div, case quando div = 'fail' e 'FAIL' else 'PASSED' end, * a partir de marcas agrupadas nocase acima não funcionou Estou fazendo algo errado?
Thunder
7
Uma coisa a notar que me tropeçou: select * from tbl where firstname='john' and lastname='doe' COLLATE NOCASEserá caso insensitivo lastname. Para ser insensível caso em firstname, escreva o seguinte: select * from tbl where firstname='john' COLLATE NOCASE and lastname='doe'. É específico para essa coluna, não para a wherecláusula inteira .
James Toomey
148
SELECT * FROM ... WHERE name = 'someone' COLLATE NOCASE
Craz
fonte
5
Se você é como eu e deseja mais documentação sobre Agrupamento, pode encontrá-lo aqui nesta página: sqlite.org/datatype3.html Basta rolar para a # 6.0
será
47

Você pode fazer assim:

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

(Não é a solução, mas em alguns casos é muito conveniente)

"O operador LIKE faz uma comparação de correspondência de padrões. O operando à direita contém o padrão, o operando à esquerda contém a string para corresponder ao padrão. Um símbolo de porcentagem ("% ") no padrão corresponde a qualquer sequência de zero ou mais caracteres na string. Um sublinhado ("_") no padrão corresponde a qualquer caractere único na string. Qualquer outro caractere corresponde a si mesmo ou a seu equivalente em maiúsculas / minúsculas (ou seja, correspondência sem distinção entre maiúsculas e minúsculas ) . (Um erro: o SQLite entende apenas maiúsculas / minúsculas para caracteres ASCII. O operador LIKE diferencia maiúsculas de minúsculas de caracteres unicode que estão além do intervalo ASCII. Por exemplo, a expressão 'a' LIKE 'A' é TRUE, mas 'æ' LIKE 'Æ'é falso.)."

Nick Dandoulakis
fonte
@ MM-BB sim, a menos que executemos o LIKE em uma coluna declarada (ou indexada) como COLLATE NOCASE, ele fará uma varredura completa das linhas.
Nick Dandoulakis
1
Não é um bug, é uma limitação documentada. A mesma página citada na resposta menciona a extensão ICU que gerencia caracteres unicode. (Talvez não foi o caso em 2009)
stenci
40

Isso não é específico para o sqlite, mas você pode simplesmente fazer

SELECT * FROM ... WHERE UPPER(name) = UPPER('someone')
oscarkuo
fonte
A outra parte da preocupação com o desempenho é encontrar as linhas correspondentes na tabela. O SQLite3 suporta índices baseados em funções? Indexar a coluna ou expressão de pesquisa (por exemplo, "MAIOR (nome)") em uma situação como essa geralmente é uma boa idéia.
cheduardo
13
Cuidado com este, como cheduardo sugeriu, o SQLite não pode usar um índice em 'name' ao executar esta consulta. O mecanismo db precisará varrer completamente todas as linhas, convertendo todos os campos 'name' para maiúsculas e executando a comparação.
Mathew Waters
1
@ quantidade, sim, muito.
The Berga
4

Outra opção é criar seu próprio agrupamento personalizado. Você pode definir esse agrupamento na coluna ou adicioná-lo às suas cláusulas de seleção. Será usado para pedidos e comparações.

Isso pode ser usado para criar 'VOILA' LIKE 'voilà'.

http://www.sqlite.org/capi3ref.html#sqlite3_create_collation

A função de intercalação deve retornar um número inteiro que seja negativo, zero ou positivo se a primeira cadeia for menor que, igual a ou maior que a segunda, respectivamente.

Nick Ericson
fonte
2

Outra opção que pode ou não fazer sentido no seu caso, é realmente ter uma coluna separada com valores com a pontuação mais baixa da sua coluna existente. Isso pode ser preenchido usando a função SQLite LOWER(), e você pode executar a correspondência nessa coluna.

Obviamente, ele adiciona redundância e um potencial de inconsistência, mas se seus dados são estáticos, pode ser uma opção adequada.

Magnus W
fonte
2

Simplesmente, você pode usar COLLATE NOCASE na sua consulta SELECT:

SELECT * FROM ... WHERE name = 'someone' COLLATE NOCASE
Pullat Junaid
fonte
1

Se a coluna for do tipo char, você precisará anexar o valor que está consultando com espaços, consulte esta pergunta aqui . Isso além de usar COLLATE NOCASEou uma das outras soluções (superior (), etc).

Possui AlTaiar
fonte
0

você pode usar a consulta semelhante para comparar a respectiva string com os valores da tabela.

selecione o nome da coluna em nome_tabela onde o nome da coluna é como 'valor de comparação respectivo';

Mahendranatarajan
fonte
Isso não adiciona nada ao stackoverflow.com/a/973665/2462516, que foi publicado em 2009
umasudhan
0

Está funcionando para mim Perfeitamente. SELECT NAME FROM TABLE_NAME WHERE NAME = 'test Name' COLLATE NOCASE

Shohel Rana
fonte