2009-06-10 9 views

risposta

385

è possibile utilizzare COLLATE NOCASE nella SELECT query:..

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

Additionaly, in SQLite, è possibile indicare che una colonna deve essere insensibile alle maiuscole quando si crea la tabella specificando collate nocase nella definizione della colonna (le altre opzioni sono binary (impostazione predefinita) e rtrim; vedi here). È possibile specificare collate nocase anche quando si crea un indice. Ad esempio:

 
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); 

espressioni che comportano Test.Text_Value dovrebbe ora essere case insensitive. Ad esempio:

 
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'ottimizzatore può anche potenzialmente utilizzare l'indice per la ricerca e la corrispondenza senza distinzione tra maiuscole e minuscole nella colonna. È possibile controllare questo usando il comando explain SQL, ad es .:

 
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            
+12

Dopo aver ricreato la tabella con 'COLLATE NOCASE', ho notato che era _much_ più veloce della query WHERE name = 'someone' COLLATE NOCASE. MOLTO più veloce (da sei a 10 volte, grosso modo?) – DefenestrationDay

+6

Secondo la documentazione, non è necessario aggiungere 'COLLATE NOCASE' all'indice se il campo stesso ha già definito questa regola di confronto: "[* La sequenza di confronto predefinita è la sequenza di confronto definito per quella colonna nell'istruzione CREATE TABLE. *] (http://www.sqlite.org/lang_createindex.html) " – Heinzi

+19

' COLLATE NOCASE' funzionerà solo con testo ASCII. Una volta che hai "FIANCÉ" o "voilà" nei valori della colonna, non corrisponderà a "fidanzato" o "VOILA". Dopo aver abilitato l'estensione ICU, ['LIKE' diventa insensibile alle maiuscole/minuscole] (http://www.sqlite.org/src/artifact?ci=trunk&filename=ext/icu/README.txt), quindi' 'FIANCÉ' LIKE ' il fidanzato è vero, ma "VOILA 'LIKE' voilà'' è ancora falso. E ICU + LIKE ha lo svantaggio di non usare l'indice, quindi può essere lento sui grandi tavoli. –

32

Questo non è specifico per SQLite, ma si può solo fare

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

C'è qualche perdita di prestazioni in questo modo? – quantity

+0

L'altra parte del problema di prestazioni è trovare le righe corrispondenti nella tabella. SQLite3 supporta indici basati su funzioni? L'indicizzazione della colonna o dell'espressione di ricerca (ad esempio "UPPER (nome)") in una situazione come questa è solitamente una buona idea. – cheduardo

+9

Attenzione con questo, come Cheduardo suggerito, SQLite non può fare uso di un indice su 'nome' quando si esegue questa query. Il motore db dovrà eseguire la scansione completa di tutte le righe, convertendo tutti i campi "nome" in maiuscolo e eseguendo il confronto. –

37

È possibile farlo in questo modo:

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

(non è la soluzione, ma in alcuni casi è molto conveniente)

"The LIKE opera tor fa un modello confronto corrispondenza. L'operando su a destra contiene il modello, l'operando sinistro contiene la stringa da abbinare al modello. Un simbolo di percentuale percento ("%") nel modello corrisponde a qualsiasi sequenza di zero o più caratteri nella stringa. Un carattere di sottolineatura ("_") nel modello corrisponde a qualsiasi singolo carattere nella stringa . Qualsiasi altro carattere corrisponde stessa o è inferiore/superiore caso equivalente (cioè case-insensitive corrispondenza). (A errore: SQLite solo capisce caso superiore/inferiore per ASCII caratteri L'operatore LIKE è caso sensibile per caratteri Unicode che sono oltre l'intervallo ASCII Ad esempio, l'espressione 'un' COME 'A' è.. TRUE ma 'Æ' LIKE 'Æ' è FALSE) "

+0

@ MM-BB sì, a meno che non eseguiamo il LIKE su una colonna dichiarata (o indicizzata) come COLLATE NOCASE, eseguirà una scansione completa delle righe. –

+0

Non è un bug, è un limite documentato. La stessa pagina citata nella risposta menziona l'estensione ICU che gestisce i caratteri Unicode. (Forse non era il caso nel 2009) – stenci

140
SELECT * FROM ... WHERE name = 'someone' COLLATE NOCASE 
+3

Se sei come me e vuoi più documentazione su Collating, puoi trovarlo qui in questa pagina: http: //www.sqlite.org/datatype3.html Basta scorrere down to # 6.0 – Will

0

Se la colonna è di tipo char allora avete bisogno di aggiungere il valore che si sta eseguendo la query con spazi, si prega di fare riferimento a questa domanda here.Questo oltre a utilizzare COLLATE NOCASE o una delle altre soluzioni (superiore(), ecc.).

2

Un'altra opzione è creare le proprie regole di confronto personalizzate. È quindi possibile impostare le regole di confronto sulla colonna o aggiungerle alle clausole di selezione. Sarà usato per ordini e confronti.

Questo può essere utilizzato per rendere 'VOILA' LIKE 'voilà'.

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

La funzione di fascicolazione deve restituire un intero che è negativo, zero o positivo se la prima stringa è inferiore, uguale o maggiore del secondo, rispettivamente.

1

Un'altra opzione che può o non ha senso nel tuo caso, è di avere effettivamente una colonna separata con valori pre-sottoeseguiti della colonna esistente. Questo può essere popolato usando la funzione SQLite LOWER(), e puoi quindi eseguire la corrispondenza su questa colonna.

Ovviamente, aggiunge ridondanza e potenziale incoerenza, ma se i dati sono statici potrebbe essere un'opzione adatta.

0

è possibile utilizzare la query simile per confrontare la rispettiva stringa con valori di tabella.

selezionare il nome della colonna da table_name dove nome colonna come 'rispettivo valore di confronto';

-1

Funziona perfettamente per me. SELECT NAME FROM TABLE_NAME WHERE NAME = 'test Name' COLLATE NOCASE

Problemi correlati