Jak ustawić Sqlite3 na rozróżnianie wielkości liter podczas porównywania ciągów?


305

Chcę wybrać rekordy z bazy danych sqlite3 poprzez dopasowanie ciągów. Ale jeśli użyję „=” w klauzuli where, stwierdzę, że w sqlite3 rozróżniana jest wielkość liter. Czy ktoś może mi powiedzieć, jak używać ciągów porównujących wielkość liter bez rozróżniania wielkości liter?

Odpowiedzi:


493

Możesz użyć COLLATE NOCASEw swoim SELECTzapytaniu:

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

Dodatkowo w SQLite możesz wskazać, że podczas tworzenia tabeli kolumna nie rozróżnia wielkości liter, określając collate nocasedefinicję kolumny (inne opcje to binary(domyślne) i rtrim; patrz tutaj ). Możesz również określić, collate nocasekiedy tworzysz indeks. Na przykład:

Utwórz test tabeli
(
  Text_Value tekst zestawia nocase
);

wstawić do wartości testowych („A”);
wstawić do wartości testowych („b”);
wstawić do wartości testowych („C”);

utwórz indeks Test_Text_Value_Index
  w teście (Text_Value zestawiać nocase);

Wyrażenia obejmujące nie Test.Text_Valuepowinny uwzględniać wielkości liter. Na przykład:

sqlite> wybierz Text_Value z Test gdzie Text_Value = 'B';
Text_Value      
----------------
b               

sqlite> wybierz Text_Value z zlecenia Test według Text_Value;
Text_Value      
----------------
ZA               
b               
do    

sqlite> wybierz Text_Value z Kolejność testowa według Text_Value desc;
Text_Value      
----------------
do               
b               
ZA               

Optymalizator może również potencjalnie wykorzystywać indeks do wyszukiwania i dopasowywania bez rozróżniania wielkości liter w kolumnie. Możesz to sprawdzić za pomocą explainpolecenia SQL, np .:

sqlite> wyjaśnij wybierz Text_Value z Test gdzie Text_Value = 'b';
adres kodowy p1 p2 p3                               
---------------- -------------- ---------- ---------- ---------------------------------
0 Idź 0 16                                           
1 liczba całkowita 0 0                                            
2 OpenRead 1 3 keyinfo (1, NOCASE)                
3 SetNumColumns 1 2                                            
4 Ciąg 8 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 Kolumna 1 0                                            
12 Oddzwonienie 1 0                                            
13 Dalej 1 9                                            
14 Zamknij 1 0                                            
15 Zatrzymanie 0 0                                            
16 Transakcja 0 0                                            
17 VerifyCookie 0 4                                            
18 Idź do 0 1                                            
19 Noop 0 0                                            

20
Po (ponownym) utworzeniu tabeli za pomocą „COLLATE NOCASE” zauważyłem, że było to znacznie szybsze niż zapytanie WHERE name = „ktoś” COLLATE NOCASE. DUŻO szybciej (sześć do 10 razy, mniej więcej?)
DefenestrationDay

10
Zgodnie z dokumentacją dodawanie COLLATE NOCASEdo indeksu nie jest wymagane, jeśli samo pole ma już zdefiniowane to zestawienie: „ Domyślną sekwencją zestawiania jest sekwencja zestawiania zdefiniowana dla tej kolumny w instrukcji CREATE TABLE.
Heinzi

29
COLLATE NOCASEbędzie działać tylko z tekstem ASCII. Gdy w kolumnach pojawi się napis „FIANCÉ” lub „voilà”, nie będzie on pasował do „narzeczonego” lub „VOILA”. Po włączeniu rozszerzenia ICU LIKEstaje się bez rozróżniania wielkości liter , więc 'FIANCÉ' LIKE 'fiancé'jest to prawda, ale 'VOILA' LIKE 'voilà'nadal jest fałszywe. ICU + LIKE ma tę wadę, że nie używa indeksu, więc może być powolny na dużych stołach.

wybierz div, przypadek, gdy div = „fail”, to „FAIL”, inaczej „PASSED” koniec, * od znaczników zestawia nocase powyżej nie działało Czy robię coś źle?
Thunder

7
Jedną z rzeczy, które mnie potknęły: select * from tbl where firstname='john' and lastname='doe' COLLATE NOCASEbędzie rozróżnianie wielkości liter lastname. Aby być niewrażliwy na przypadek firstname, to napisać: select * from tbl where firstname='john' COLLATE NOCASE and lastname='doe'. Jest specyficzny dla tej jednej kolumny, a nie całej whereklauzuli.
James Toomey

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

5
Jeśli jesteś podobny do mnie i chcesz więcej dokumentacji na temat zestawiania, możesz ją znaleźć tutaj na tej stronie: sqlite.org/datatype3.html Wystarczy przewinąć w dół do # 6.0
będzie

47

Możesz to zrobić w następujący sposób:

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

(To nie jest rozwiązanie, ale w niektórych przypadkach jest bardzo wygodne)

„ Operator LIKE porównuje dopasowanie wzorca. Operand po prawej stronie zawiera wzorzec, operand po lewej zawiera ciąg pasujący do wzorca. Symbol procentu („% ”) we wzorcu odpowiada dowolnej sekwencji zerowej lub większej znaków w ciągu. Podkreślenie („_”) we wzorcu pasuje do każdego pojedynczego znaku w ciągu. Każdy inny znak pasuje do siebie lub jego odpowiednika z małymi / dużymi literami (tj. dopasowanie bez rozróżniania wielkości liter ) . (Błąd: SQLite tylko rozumie wielkie / małe litery dla znaków ASCII. Operator LIKE rozróżnia małe i wielkie litery dla znaków Unicode, które są poza zakresem ASCII. Na przykład wyrażenie „a” LIKE ”A jest PRAWDA, ale„ æ ”LIKE” Æ ”to fałsz.)."


@ MM-BB tak, chyba że wykonamy PODOBNE do kolumny, która jest zadeklarowana (lub zindeksowana) jako COLLATE NOCASE, wykona pełny skan wierszy.
Nick Dandoulakis

1
To nie jest błąd, to udokumentowane ograniczenie. Ta sama strona cytowana w odpowiedzi wspomina o rozszerzeniu ICU, które zarządza znakami Unicode. (Być może nie było tak w 2009 roku)
stenci

40

Nie jest to specyficzne dla sqlite, ale możesz po prostu to zrobić

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

Inną częścią problemu z wydajnością jest znalezienie pasujących wierszy w tabeli. Czy SQLite3 obsługuje indeksy oparte na funkcjach? Indeksowanie kolumny wyszukiwania lub wyrażenia (np. „UPPER (nazwa)”) w takiej sytuacji jest zwykle dobrym pomysłem.
cheduardo

13
Uważaj na ten, jak wskazał Cheduardo, SQLite nie może korzystać z indeksu na „name” podczas uruchamiania tego zapytania. Silnik db będzie musiał wykonać pełne skanowanie wszystkich wierszy, przekonwertować wszystkie pola „name” na wielkie litery i uruchomić porównanie.
Mathew Waters,

1
@ ilość, tak, dużo.
Berga,

4

Inną opcją jest utworzenie własnego sortowania niestandardowego. Następnie możesz ustawić to sortowanie w kolumnie lub dodać je do wybranych klauzul. Będzie on używany do zamawiania i porównań.

Można to wykorzystać do wytworzenia „VOILA” LIKE „voilà”.

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

Funkcja zestawiania musi zwracać liczbę całkowitą, która jest ujemna, zero lub dodatnia, jeśli pierwszy ciąg jest odpowiednio mniejszy, równy lub większy niż drugi.


2

Inną opcją, która może, ale nie musi mieć sensu w twoim przypadku, jest posiadanie osobnej kolumny z wcześniej obniżonymi wartościami istniejącej kolumny. Można to wypełnić za pomocą funkcji SQLite LOWER(), a zamiast tego można wykonać dopasowanie w tej kolumnie.

Oczywiście dodaje to nadmiarowości i potencjalnie może powodować niespójność, ale jeśli dane są statyczne, może to być odpowiednia opcja.


2

Po prostu możesz użyć COLLATE NOCASE w zapytaniu SELECT:

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

1

Jeśli kolumna jest typu, charto musisz dodać spację do kwerendy, zapoznaj się z tym pytaniem tutaj . To oprócz użycia COLLATE NOCASElub jednego z innych rozwiązań (górny () itp.).



0

Działa dla mnie doskonale. SELECT NAME FROM TABLE_NAME WHERE NAME = 'test Name' COLLATE NOCASE

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.