Как настроить 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                                            
cheduardo
источник
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
Craz
источник
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')
oscarkuo
источник
Другая часть проблемы производительности - поиск подходящих строк в таблице. Поддерживает ли SQLite3 индексы на основе функций? Индексирование поискового столбца или выражения (например, «UPPER (имя)») в такой ситуации обычно является хорошей идеей.
cheduardo
13
Остерегайтесь этого, как намекнул Чедуардо, SQLite не может использовать индекс «имя» при выполнении этого запроса. Механизму БД потребуется полностью отсканировать все строки, преобразовать все поля «name» в верхний регистр и выполнить сравнение.
Мэтью Уотерс
1
@ да, много.
Берга
4

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

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

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

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

Ник Эриксон
источник
2

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

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

Магнус W
источник
2

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

SELECT * FROM ... WHERE name = 'someone' COLLATE NOCASE
Пуллат Джунаид
источник
1

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

Имеет альтайар
источник
0

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

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

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

Это работает для меня отлично. SELECT NAME FROM TABLE_NAME WHERE NAME = 'test Name' COLLATE NOCASE

Шохел Рана
источник