Bagaimana mengatur Sqlite3 menjadi case-sensitive ketika string membandingkan?

305

Saya ingin memilih catatan dari database sqlite3 dengan pencocokan string. Tetapi jika saya menggunakan '=' di mana klausa, saya menemukan bahwa sqlite3 peka huruf besar-kecil. Adakah yang bisa memberi tahu saya cara menggunakan string yang membandingkan case-insensitive?

kuantitas
sumber

Jawaban:

493

Anda dapat menggunakan COLLATE NOCASEdalam SELECTpermintaan Anda :

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

Selain itu, dalam SQLite, Anda bisa menunjukkan bahwa kolom harus peka huruf besar-kecil ketika Anda membuat tabel dengan menentukan collate nocasedalam definisi kolom (opsi lain adalah binary(default) dan rtrim; lihat di sini ). Anda dapat menentukan collate nocasekapan Anda membuat indeks juga. Sebagai contoh:

buat tabel Test
(
  Text_Value menyusun teks nocase
);

masukkan ke dalam nilai Test ('A');
masukkan ke dalam nilai Test ('b');
masukkan ke dalam nilai Test ('C');

buat indeks Test_Text_Value_Index
  pada Uji (Text_Value collate nocase);

Ekspresi yang melibatkan Test.Text_Valuesekarang harus peka huruf besar-kecil. Sebagai contoh:

sqlite> pilih Text_Value dari Test di mana Text_Value = 'B';
Text_Value      
----------------
b               

sqlite> pilih Text_Value dari Test order oleh Text_Value;
Text_Value      
----------------
SEBUAH               
b               
C    

sqlite> pilih Text_Value dari Test order oleh Text_Value desc;
Text_Value      
----------------
C               
b               
SEBUAH               

Pengoptimal juga dapat berpotensi menggunakan indeks untuk pencarian dan pencocokan case-sensitive pada kolom. Anda dapat memeriksa ini menggunakan explainperintah SQL, misalnya:

sqlite> jelaskan pilih Text_Value dari Tes di mana 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 Kolom 1 0                                            
12 Panggilan Balik 1 0                                            
13 Selanjutnya 1 9                                            
14 Tutup 1 0                                            
15 Berhenti 0 0                                            
16 Transaksi 0 0                                            
17 VerifyCookie 0 4                                            
18 Goto 0 1                                            
19 Noop 0 0                                            
cheduardo
sumber
20
Setelah (kembali) membuat tabel dengan 'COLLATE NOCASE', saya perhatikan itu jauh lebih cepat daripada permintaan WHERE name = 'seseorang' COLLATE NOCASE. JAUH lebih cepat (enam hingga 10 kali, kira-kira?)
DefenestrationDay
10
Menurut dokumentasi, menambahkan COLLATE NOCASEke indeks tidak diperlukan jika bidang itu sendiri sudah memiliki susunan ini: " Urutan susun bawaan adalah urutan susun yang ditentukan untuk kolom itu dalam pernyataan CREATE TABLE. "
Heinzi
29
COLLATE NOCASEhanya akan bekerja dengan teks ASCII. Setelah Anda memiliki "FIANCÉ" atau "voilà" di nilai kolom Anda, itu tidak akan cocok dengan "tunangan" atau "VOILA". Setelah mengaktifkan ekstensi ICU, LIKEmenjadi case-insensitive , jadi 'FIANCÉ' LIKE 'fiancé'benar, tetapi 'VOILA' LIKE 'voilà'masih salah. Dan ICU + LIKE memiliki kelemahan karena tidak menggunakan indeks, sehingga bisa lambat pada tabel besar.
pilih div, case ketika div = 'gagal' lalu 'GAGAL' lain 'LULUS' berakhir, * dari tanda susun nocase di atas tidak berfungsi apakah saya melakukan sesuatu yang salah?
Guntur
7
Satu hal yang perlu diperhatikan yang membuat saya tersandung: select * from tbl where firstname='john' and lastname='doe' COLLATE NOCASEakan case case on sensitive lastname. Menjadi kasus sensitif pada firstname, menulis ini: select * from tbl where firstname='john' COLLATE NOCASE and lastname='doe'. Ini khusus untuk satu kolom, bukan seluruh whereklausa.
James Toomey
148
SELECT * FROM ... WHERE name = 'someone' COLLATE NOCASE
Gila
sumber
5
Jika Anda seperti saya dan ingin lebih banyak dokumentasi tentang Mengumpulkan, Anda dapat menemukannya di sini di halaman ini: sqlite.org/datatype3.html Cukup gulir ke bawah ke # 6.0
Will
47

Anda dapat melakukannya seperti ini:

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

(Ini bukan yang solusi, tetapi dalam beberapa kasus sangat nyaman)

" Operator LIKE melakukan perbandingan pola yang cocok. Operan ke kanan berisi pola, operan kiri berisi string yang cocok dengan pola. Simbol persen ("% ") dalam pola cocok dengan urutan nol atau lebih karakter dalam string. Garis bawah ("_") dalam pola cocok dengan karakter tunggal apa pun dalam string. Karakter lainnya cocok dengan dirinya sendiri atau setara dengan huruf kecil / huruf besar (yaitu pencocokan case-insensitive ) . (Bug: SQLite hanya mengerti huruf besar / kecil untuk karakter ASCII. Operator LIKE peka huruf besar-kecil untuk karakter unicode yang berada di luar rentang ASCII. Misalnya, ekspresi 'a' LIKE 'A' BENAR tetapi 'æ' LIKE 'Æ'adalah FALSE.). "

Nick Dandoulakis
sumber
@ MM-BB ya, kecuali kita melakukan LIKE pada kolom yang dinyatakan (atau diindeks) sebagai COLLATE NOCASE, itu akan melakukan pemindaian penuh pada baris.
Nick Dandoulakis
1
Ini bukan bug, ini adalah batasan yang terdokumentasi. Halaman yang sama dikutip dalam jawaban menyebutkan ekstensi ICU yang mengelola karakter unicode. (Mungkin bukan itu yang terjadi pada 2009)
stenci
40

Ini tidak khusus untuk sqlite tetapi Anda bisa melakukannya

SELECT * FROM ... WHERE UPPER(name) = UPPER('someone')
oscarkuo
sumber
Bagian lain dari kekhawatiran kinerja adalah menemukan baris yang cocok dalam tabel. Apakah SQLite3 mendukung indeks berbasis fungsi? Mengindeks kolom pencarian atau ekspresi (mis. "UPPER (nama)") dalam situasi seperti ini biasanya merupakan ide yang bagus.
cheduardo
13
Berhati-hatilah dengan yang ini, seperti yang ditunjukkan oleh cheduardo, SQLite tidak dapat menggunakan indeks pada 'nama' saat menjalankan kueri ini. Mesin db perlu memindai seluruh baris, mengonversi semua bidang 'nama' menjadi huruf besar dan menjalankan perbandingan.
Mathew Waters
1
@jumlah, ya, banyak.
The Berga
4

Pilihan lain adalah membuat koleksi kustom Anda sendiri. Anda kemudian dapat mengatur susunan itu pada kolom atau menambahkannya ke klausa pilih Anda. Ini akan digunakan untuk pemesanan dan perbandingan.

Ini dapat digunakan untuk membuat 'VOILA' LIKE 'voilà'.

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

Fungsi susun harus mengembalikan bilangan bulat yang negatif, nol, atau positif jika string pertama kurang dari, sama dengan, atau lebih besar dari yang kedua.

Nick Ericson
sumber
2

Pilihan lain yang mungkin atau mungkin tidak masuk akal dalam kasus Anda, adalah untuk benar-benar memiliki kolom terpisah dengan nilai pra-rendahnya kolom Anda yang ada. Ini dapat diisi menggunakan fungsi SQLite LOWER(), dan Anda kemudian dapat melakukan pencocokan pada kolom ini.

Jelas, ini menambah redundansi dan potensi inkonsistensi, tetapi jika data Anda statis, itu mungkin pilihan yang cocok.

Magnus W
sumber
2

Cukup, Anda dapat menggunakan COLLATE NOCASE dalam permintaan SELECT Anda:

SELECT * FROM ... WHERE name = 'someone' COLLATE NOCASE
Pullat Junaid
sumber
1

Jika kolom bertipe charmaka Anda perlu menambahkan nilai yang Anda tanyakan spasi, silakan lihat pertanyaan ini di sini . Ini selain menggunakan COLLATE NOCASEatau salah satu solusi lain (atas (), dll).

Memiliki AlTaiar
sumber
0

Anda bisa menggunakan query seperti untuk membandingkan string masing-masing dengan tabel tabel.

pilih nama kolom dari table_name di mana nama kolom seperti 'masing-masing nilai pembanding';

Mahendranatarajan
sumber
Ini tidak menambahkan apa pun ke stackoverflow.com/a/973665/2462516 yang diposting pada 2009
umasudhan
0

Ini bekerja untuk saya. Sempurna. SELECT NAME FROM TABLE_NAME WHERE NAME = 'test Name' COLLATE NOCASE

Shohel Rana
sumber