Как настроить Sqlite3 без учета регистра при сравнении строк?


305

Я хочу выбрать записи из базы данных sqlite3 путем сопоставления строк. Но если я использую '=' в предложении where, я обнаружу, что sqlite3 чувствителен к регистру. Может кто-нибудь сказать мне, как использовать сравнение строк без учета регистра?

Ответы:


493

Вы можете использовать COLLATE NOCASEв своем SELECTзапросе:

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

Кроме того, в SQLite вы можете указать, что столбец должен быть нечувствительным к регистру при создании таблицы, указав collate nocaseв определении столбца (другие параметры binary(по умолчанию) и rtrim; см. Здесь ). Вы также можете указать collate nocaseпри создании индекса. Например:

создать таблицу Test
(
  Text_Value text collate nocase
);

вставить в тестовые значения ('A');
вставить в тестовые значения ('b');
вставить в тестовые значения ('C');

создать индекс Test_Text_Value_Index
  на тесте (Text_Value collate nocase);

Выражения с участием Test.Text_Valueтеперь должны быть без учета регистра. Например:

sqlite> выберите Text_Value из Test, где Text_Value = 'B';
TEXT_VALUE      
----------------
б               

sqlite> выберите Text_Value из тестового заказа по Text_Value;
TEXT_VALUE      
----------------               
б               
С    

sqlite> выберите Text_Value в тестовом порядке по Text_Value desc;
TEXT_VALUE      
----------------
С               
б                              

Оптимизатор также может использовать индекс для поиска и сопоставления без учета регистра в столбце. Вы можете проверить это с помощью команды explainSQL, например:

sqlite> объяснение, выберите Text_Value из Test, где Text_Value = 'b';
код операции addr p1 p2 p3                               
---------------- -------------- ---------- ---------- ---------------------------------
0 Перейти 0 16                                           
1 целое число 0 0                                            
2 OpenRead 1 3 keyinfo (1, NOCASE)                
3 SetNumColumns 1 2                                            
4 Строка8 0 0 б                                
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 Колонка 1 0                                            
12 Обратный звонок 1 0                                            
13 Следующий 1 9                                            
14 Закрыть 1 0                                            
15 Останов 0 0                                            
16 Транзакция 0 0                                            
17 VerifyCookie 0 4                                            
18 Перейти 0 1                                            
19 Нооп 0 0                                            

20
После (пере) создания таблицы с помощью 'COLLATE NOCASE' я заметил, что это было намного быстрее, чем запрос WHERE name = 'somebody' COLLATE NOCASE. НАМНОГО быстрее (от шести до 10 раз, примерно?)
— DefenestrationDay

10
Согласно документации, добавление COLLATE NOCASEк индексу не требуется, если в самом поле уже определено это сопоставление: « Последовательность упорядочения по умолчанию - это последовательность упорядочения, определенная для этого столбца в операторе CREATE TABLE. »
— Хайнци

29
COLLATE NOCASEбудет работать только с текстом ASCII. Если в ваших значениях столбца указано «FIANCÉ» или «voilà», оно не будет совпадать с «fiancé» или «VOILA». После включения расширения ICU LIKEстановится нечувствительным к регистру , так что 'FIANCÉ' LIKE 'fiancé'это правда, но 'VOILA' LIKE 'voilà'все еще ложь. И у ICU + LIKE есть недостаток - не использовать индекс, поэтому он может быть медленным на больших таблицах.

выберите div, случай, когда div = 'fail', затем 'FAIL', в противном случае 'PASSED' end, * из отмеченных выше значений collate nocase не сработало, я что-то не так делаю?
— Гром

7
Одна вещь, чтобы отметить, что сбило меня с толку: select * from tbl where firstname='john' and lastname='doe' COLLATE NOCASEбудет без учета регистра lastname. Чтобы быть чувствительны к регистру на firstname, написать это: select * from tbl where firstname='john' COLLATE NOCASE and lastname='doe'. Это относится только к одному столбцу, а не ко всему whereпредложению.
— Джеймс Туми

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

5
Если вы похожи на меня и хотите больше документации по сортировке, вы можете найти ее здесь на этой странице: sqlite.org/datatype3.html Просто прокрутите вниз до # 6.0
— Будет

47

Вы можете сделать это так:

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

(Это не решение, но в некоторых случаях очень удобно)

«Оператор LIKE выполняет сравнение сопоставления с шаблоном. Операнд справа содержит шаблон, левый операнд содержит строку для сопоставления с шаблоном. Символ процента («% ») в шаблоне соответствует любой последовательности от нуля или более символы в строке. Подчеркивание ("_") в шаблоне соответствует любому отдельному символу в строке. Любой другой символ соответствует самому себе или его эквиваленту в нижнем / верхнем регистре (т. е. нечувствительное к регистру совпадение) . (Ошибка: SQLite понимает только прописные / строчные буквы для символов ASCII. Оператор LIKE чувствителен к регистру символов Unicode, выходящих за пределы диапазона ASCII. Например, выражение 'a' LIKE 'A' имеет значение TRUE, но 'æ' LIKE 'Æ'ЛОЖЬ.)


@ MM-BB да, если мы не выполним LIKE для столбца, который объявлен (или проиндексирован) как COLLATE NOCASE, он выполнит полное сканирование строк.
— Ник Дандулакис

1
Это не ошибка, это задокументированное ограничение. На той же странице, указанной в ответе, упоминается расширение ICU, которое управляет символами Юникода. (Возможно, это было не так в 2009 году)
— stenci

40

Это не относится к sqlite, но вы можете просто сделать

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

Другая часть проблемы производительности - поиск подходящих строк в таблице. Поддерживает ли SQLite3 индексы на основе функций? Индексирование поискового столбца или выражения (например, «UPPER (имя)») в такой ситуации обычно является хорошей идеей.
— cheduardo

13
Остерегайтесь этого, как намекнул Чедуардо, SQLite не может использовать индекс «имя» при выполнении этого запроса. Механизму БД потребуется полностью отсканировать все строки, преобразовать все поля «name» в верхний регистр и выполнить сравнение.
— Мэтью Уотерс

1
@ да, много.
— Берга

4

Другой вариант - создать свой собственный порядок сортировки. Затем вы можете установить это сопоставление в столбце или добавить его к выбранным предложениям. Он будет использоваться для упорядочивания и сравнения.

Это может быть использовано, чтобы сделать 'VOILA' LIKE 'voilà'.

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

Функция сортировки должна возвращать целое число, которое является отрицательным, нулевым или положительным, если первая строка меньше, равна или больше второй, соответственно.


2

Другой вариант, который может иметь или не иметь смысла в вашем случае, это фактически иметь отдельный столбец с предварительно заниженными значениями существующего столбца. Это можно заполнить с помощью функции SQLite LOWER(), и вы можете вместо этого выполнить сопоставление для этого столбца.

Очевидно, что это добавляет избыточность и возможность несогласованности, но если ваши данные статичны, это может быть подходящим вариантом.



1

Если столбец имеет тип, charвам необходимо добавить значение, которое вы запрашиваете, с пробелами, пожалуйста, обратитесь к этому вопросу здесь . Это в дополнение к использованию COLLATE NOCASEили одного из других решений (upper () и т. Д.).


0

Вы можете использовать подобный запрос для сравнения соответствующей строки с табличными значениями.

выберите имя столбца из table_name, где имя столбца, как «соответствующее значение сравнения»;


Это ничего не добавляет к stackoverflow.com/a/973665/2462516, который был размещен в 2009 году
— umasudhan

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.