Як встановити Sqlite3 таким, що не враховує регістр при порівнянні рядків?


305

Я хочу вибрати записи з бази даних sqlite3 шляхом відповідності рядків. Але якщо я використовую '=' у пункті де, я виявив, що sqlite3 чутливий до регістру. Хто-небудь може сказати мені, як використовувати рядки, що порівнюють регістр, нечутливий?

Відповіді:


493

Ви можете використовувати COLLATE NOCASEу своєму SELECTзапиті:

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

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

Створити таблицю Тест
(
  Text_Value текст порівняння nocase
);

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

створити індекс Test_Text_Value_Index
  тестування (Text_Value collate nocase);

Test.Text_ValueТепер вирази, що стосуються, повинні бути нечутливими до регістру. Наприклад:

sqlite> виберіть Text_Value з Тесту, де Text_Value = 'B';
Text_Value      
----------------
б               

sqlite> виберіть Text_Value з тестового замовлення Text_Value;
Text_Value      
----------------
А               
б               
С    

sqlite> виберіть Text_Value з тестового замовлення за текстовим описом Text_Value;
Text_Value      
----------------
С               
б               
А               

Оптимізатор також може потенційно використовувати індекс для нечутливого до регістру пошуку та зіставлення стовпця. Ви можете перевірити це за допомогою команди explainSQL, наприклад:

sqlite> поясніть, виберіть Text_Value з Тесту, де Text_Value = 'b';
addr opcode p1 p2 p3                               
---------------- -------------- ---------- ---------- ---------------------------------
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 Перехід 1 1                                            
19 Ніп 0 0                                            

20
Після (повторного) створення таблиці за допомогою "COLLATE NOCASE" я помітив, що це набагато швидше, ніж запит WHERE name = 'who' COLLATE NOCASE. МНОГО швидше (шість-10 разів, приблизно?)
DefenestrationДень

10
Згідно з документацією, додавання COLLATE NOCASEдо індексу не потрібно, якщо в самому полі вже визначено це зіставлення: " Послідовність згортання за замовчуванням - це послідовність згортання, визначена для цього стовпця в операторі CREATE TABLE ".
Хайнзі

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

виберіть div, випадок, коли div = 'fail', то 'FAIL' else 'PASSED' end, * з позначок порівнюйте 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
Якщо ви схожі на мене і хочуть більше документації на Collating, ви можете знайти його тут , на цій сторінці: sqlite.org/datatype3.html Просто перейдіть до # 6,0
Will

47

Ви можете це зробити так:

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

(Це не рішення, але в деяких випадках дуже зручно)

"Оператор LIKE робить порівняння порівняння шаблонів. Операнд праворуч містить шаблон, операнд ліворуч містить рядок, який повинен відповідати шаблону. Символ відсотків ("% ") у шаблоні відповідає будь-якій послідовності нуля або більше символів у рядку. Підкреслення ("_") у шаблоні відповідає будь-якому одному символу в рядку. Будь-який інший символ відповідає самому собі або його нижньому / верхньому регістру (тобто невідповідності регістру ) . (Помилка: SQLite розуміє лише верхній / нижній регістр символів ASCII. Оператор LIKE чутливий до регістру для символів unicode, які виходять за межі діапазону ASCII. Наприклад, вираз 'a' LIKE 'A' є ІСТИНИМ, але 'æ' LIKE 'Æ'є ЛАЖНИМ.). "


@ MM-BB так, якщо ми не виконаємо LIKE на стовпчику, який оголошено (або індексується) як COLLATE NOCASE, він здійснить повне сканування рядків.
Нік Дандолакіс

1
Це не помилка, це документоване обмеження. На цій же сторінці, що цитується у відповіді, згадується розширення ICU, яке управляє символами unicode. (Можливо, це не було так у 2009 році)
stenci

40

Це не характерно для sqlite, але ви можете просто зробити

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

Інша частина проблеми продуктивності - пошук відповідних рядків у таблиці. Чи підтримує SQLite3 індекси на основі функцій? Індексація стовпця пошуку або виразу (наприклад, "UPPER (name)") у подібній ситуації зазвичай є хорошою ідеєю.
чедуардо

13
Слідкуйте за цим, як натякнув cheduardo, SQLite не може використовувати індекс на "ім'я" під час запуску цього запиту. Двигун db повинен буде повністю сканувати всі рядки, перетворивши всі поля 'name' у верхній регістр та запустивши порівняння.
Меттью Уотерс

1
@quantity, так, багато.
Берга

4

Інший варіант - створити власне спеціальне порівняння. Потім ви можете встановити це зіставлення на стовпчик або додати його до вибраних пропозицій. Він буде використовуватися для замовлення та порівняння.

Це можна використовувати, щоб зробити "VOILA" LIKE "voilà".

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

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


2

Інший варіант, який може мати або не має сенсу у вашому випадку, - це фактично мати окремий стовпець із попередньо заниженими значеннями наявного стовпця. Це можна заповнити за допомогою функції SQLite LOWER(), а потім можна виконати відповідність у цьому стовпці.

Очевидно, це додає надмірності та потенціалу непослідовності, але якщо ваші дані статичні, це може бути підходящим варіантом.


2

Просто ви можете використовувати COLLATE NOCASE у вашому SELECT запиті:

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

1

Якщо стовпець має тип, charвам потрібно додати значення, яке ви запитуєте пробілами, зверніться до цього питання тут . Це на додаток до використання COLLATE NOCASEабо одного з інших рішень (верхнього () тощо).


0

ви можете використовувати подібний запит для порівняння відповідного рядка з валами таблиці.

виберіть ім'я стовпця з імені table_name, де ім'я стовпця типу "відповідне значення порівняння";


Це не додає нічого до stackoverflow.com/a/973665/2462516, який було розміщено у 2009 році
umasudhan

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.