วิธีการตั้งค่า Sqlite3 เป็นแบบไม่สนใจขนาดตัวพิมพ์เมื่อเปรียบเทียบสตริง


305

ฉันต้องการเลือกระเบียนจากฐานข้อมูล sqlite3 โดยการจับคู่สตริง แต่ถ้าฉันใช้ '=' ในส่วนคำสั่ง where ฉันพบว่า 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 จาก Test โดยที่ Text_Value = 'B';
TEXT_VALUE      
----------------
ข               

sqlite> เลือก Text_Value จากคำสั่งทดสอบโดย Text_Value;
TEXT_VALUE      
----------------               
ข               
ค    

sqlite> เลือก Text_Value จากคำสั่งทดสอบโดย Text_Value desc;
TEXT_VALUE      
----------------
ค               
ข                              

เครื่องมือเพิ่มประสิทธิภาพอาจใช้ประโยชน์จากดัชนีสำหรับการค้นหาและการจับคู่ตามตัวพิมพ์เล็กและใหญ่ในคอลัมน์ คุณสามารถตรวจสอบสิ่งนี้ได้โดยใช้explainคำสั่ง SQL เช่น:

sqlite> อธิบายเลือก Text_Value จาก Test โดยที่ Text_Value = 'b';
addr opcode p1 p2 p3                               
---------------- -------------- ---------- ---------- ---------------------------------
0 ไปที่ 0 16                                           
1 จำนวนเต็ม 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 คอลัมน์ 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
หลังจาก (อีกครั้ง) การสร้างตารางที่มี 'เรียง NOCASE' ผมสังเกตเห็นว่ามันเป็นมากเร็วกว่าแบบสอบถามที่ชื่อ = 'คน' เรียง NOCASE เร็วขึ้นมาก (หกถึง 10 เท่าโดยประมาณ?)
Defenestration

10
การเพิ่มCOLLATE NOCASEลงในดัชนีไม่จำเป็นถ้าฟิลด์นั้นมีการเรียงลำดับที่กำหนดไว้แล้ว: " ลำดับการเรียงเริ่มต้นคือลำดับการเรียงที่กำหนดไว้สำหรับคอลัมน์นั้นในคำสั่ง CREATE TABLE "
Heinzi

29
COLLATE NOCASEจะทำงานกับข้อความ ASCII เท่านั้น เมื่อคุณมี "FIANCÉ" หรือ "voilà" ในค่าคอลัมน์ของคุณแล้วจะไม่ตรงกับ "fiancé" หรือ "VOILA" หลังจากเปิดใช้งานส่วนขยาย ICU LIKEจะกลายเป็นตัวพิมพ์เล็กและตัวพิมพ์เล็กดังนั้นจึง'FIANCÉ' LIKE 'fiancé'เป็นความจริง แต่'VOILA' LIKE 'voilà'ก็ยังเป็นเท็จ และ ICU + LIKE มีข้อเสียเปรียบในการไม่ใช้ดัชนีดังนั้นมันอาจช้าในตารางขนาดใหญ่

เลือก div, กรณีที่เมื่อ div = 'fail' ดังนั้น 'FAIL' อื่น ๆ 'PASSED' end, * จากเครื่องหมายเรียงหน้า nocase ด้านบนไม่ทำงานฉันทำอะไรผิดหรือเปล่า?
Thunder

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ประโยค
James Toomey

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 'Æ'คือ FALSE)


@ MM-BB ใช่นอกจากว่าเราจะทำ LIKE ในคอลัมน์ที่ประกาศ (หรือจัดทำดัชนี) เป็น COLLATE NOCASE มันจะทำการสแกนแบบเต็มของแถว
Nick Dandoulakis

1
ไม่ใช่ข้อผิดพลาดมันเป็นข้อ จำกัด เอกสาร หน้าเดียวกันที่ยกมาในคำตอบที่กล่าวถึงส่วนขยาย ICU ที่จัดการอักขระ unicode (อาจจะไม่ใช่ในปี 2009)
59

40

นี่ไม่ใช่เฉพาะ sqlite แต่คุณสามารถทำได้

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

ส่วนอื่น ๆ ของความกังวลเกี่ยวกับประสิทธิภาพการทำงานคือการค้นหาแถวที่ตรงกันในตาราง SQLite3 รองรับดัชนีตามฟังก์ชั่นหรือไม่? การทำดัชนีคอลัมน์ค้นหาหรือนิพจน์ (เช่น "UPPER (ชื่อ)") ในสถานการณ์เช่นนี้มักเป็นความคิดที่ดี
cheduardo

13
ระวังด้วยอันนี้เนื่องจาก cheduardo บอกเป็นนัย SQLite ไม่สามารถใช้ดัชนีใน 'ชื่อ' เมื่อเรียกใช้แบบสอบถามนี้ เอ็นจิ้น db จะต้องสแกนเต็มทุกแถวแปลงฟิลด์ 'ชื่อ' ทั้งหมดเป็นตัวพิมพ์ใหญ่และรันการเปรียบเทียบ
Mathew Waters

1
@ ปริมาณใช่มาก
The Berga

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.