ฉันมีฟังก์ชั่นที่คืนค่าตัวอักษรห้าตัวพร้อมตัวพิมพ์เล็ก ถ้าฉันทำแบบสอบถามในสายนี้มันจะคืนค่าโดยไม่คำนึงถึงกรณี
ฉันจะทำให้สตริงเคียวรี MySQL เป็นตัวพิมพ์เล็กหรือใหญ่ได้อย่างไร?
ฉันมีฟังก์ชั่นที่คืนค่าตัวอักษรห้าตัวพร้อมตัวพิมพ์เล็ก ถ้าฉันทำแบบสอบถามในสายนี้มันจะคืนค่าโดยไม่คำนึงถึงกรณี
ฉันจะทำให้สตริงเคียวรี MySQL เป็นตัวพิมพ์เล็กหรือใหญ่ได้อย่างไร?
คำตอบ:
http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html
ชุดอักขระเริ่มต้นและการเปรียบเทียบคือ latin1 และ latin1_swedish_ci ดังนั้นการเปรียบเทียบสตริงแบบไบนารี่จึงไม่คำนึงถึงตัวพิมพ์ใหญ่และตัวพิมพ์เล็กตามค่าเริ่มต้น ซึ่งหมายความว่าหากคุณค้นหาด้วย col_name LIKE 'a%' คุณจะได้รับค่าคอลัมน์ทั้งหมดที่เริ่มต้นด้วย A หรือ a หากต้องการทำให้ตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ตรวจสอบให้แน่ใจว่าหนึ่งในตัวถูกดำเนินการมีตัวพิมพ์เล็กหรือตัวพิมพ์ใหญ่ ตัวอย่างเช่นหากคุณกำลังเปรียบเทียบคอลัมน์และสตริงที่ทั้งคู่มีชุดอักขระ latin1 คุณสามารถใช้ตัวดำเนินการ COLLATE เพื่อให้ตัวถูกดำเนินการทั้งสองมีตัวคั่น latin1_general_cs หรือ latin1_bin:
col_name COLLATE latin1_general_cs LIKE 'a%'
col_name LIKE 'a%' COLLATE latin1_general_cs
col_name COLLATE latin1_bin LIKE 'a%'
col_name LIKE 'a%' COLLATE latin1_bin
หากคุณต้องการให้คอลัมน์ได้รับการปฏิบัติในลักษณะที่คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ให้ประกาศด้วยการเปรียบเทียบขนาดตัวพิมพ์เล็กหรือใหญ่
SELECT 'email' COLLATE utf8_bin = 'Email'
ข่าวดีก็คือว่าถ้าคุณต้องการสอบถามที่เป็นกรณี ๆ ไปมันเป็นเรื่องง่ายมากที่จะทำ:
SELECT * FROM `table` WHERE BINARY `column` = 'value'
convert(char(0x65,0xcc,0x88) using utf8)
(เช่นที่e
มีการ¨
เพิ่ม) และconvert(char(0xc3,0xab) using utf8)
(ie ë
) แต่การเพิ่มBINARY
จะทำให้พวกเขาไม่เท่ากัน
คำตอบที่โพสต์โดย Craig White มีโทษประสิทธิภาพที่ยอดเยี่ยม
SELECT * FROM `table` WHERE BINARY `column` = 'value'
เพราะมันไม่ได้ใช้ดัชนี ดังนั้นทั้งคุณจำเป็นต้องเปลี่ยนการเปรียบเทียบตารางเช่นพูดถึงที่นี่https://dev.mysql.com/doc/refman/5.7/en/case-sensitivity.html
หรือ
การแก้ไขที่ง่ายที่สุดคุณควรใช้ค่า BINARY
SELECT * FROM `table` WHERE `column` = BINARY 'value'
เช่น.
mysql> EXPLAIN SELECT * FROM temp1 WHERE BINARY col1 = "ABC" AND col2 = "DEF" ;
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | temp1 | ALL | NULL | NULL | NULL | NULL | 190543 | Using where |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
VS
mysql> EXPLAIN SELECT * FROM temp1 WHERE col1 = BINARY "ABC" AND col2 = "DEF" ;
+----+-------------+-------+-------+---------------+---------------+---------+------+------+------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------------+---------+------+------+------------------------------------+
| 1 | SIMPLE | temp1 | range | col1_2e9e898e | col1_2e9e898e | 93 | NULL | 2 | Using index condition; Using where |
+----+-------------+-------+-------+---------------+---------------+---------+------+------+------------------------------------+
enter code here
1 แถวในชุด (0.00 วินาที)
แทนที่จะใช้ตัวดำเนินการ = คุณอาจต้องการใช้ LIKE หรือ LIKE BINARY
// this returns 1 (true)
select 'A' like 'a'
// this returns 0 (false)
select 'A' like binary 'a'
select * from user where username like binary 'a'
มันจะใช้ 'a' และไม่ใช่ 'A' ในสภาพของมัน
หากต้องการใช้ดัชนีก่อนใช้ BINARY คุณสามารถทำสิ่งนี้ถ้าคุณมีตารางขนาดใหญ่
SELECT
*
FROM
(SELECT * FROM `table` WHERE `column` = 'value') as firstresult
WHERE
BINARY `column` = 'value'
ข้อความค้นหาย่อยจะส่งผลให้มีชุดย่อยเล็ก ๆ เล็ก ๆ น้อย ๆ ซึ่งคุณเลือกการจับคู่แบบตรงตามตัวพิมพ์ใหญ่ - เล็ก
วิธีที่ถูกต้องที่สุดในการทำการเปรียบเทียบสตริงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่โดยไม่ต้องเปลี่ยนการเรียงของคอลัมน์ที่ถูกสอบถามคือการระบุชุดอักขระและการเปรียบเทียบอย่างชัดเจนสำหรับค่าที่คอลัมน์นั้นถูกเปรียบเทียบ
select * from `table` where `column` = convert('value' using utf8mb4) collate utf8mb4_bin;
binary
?การใช้binary
โอเปอเรเตอร์นั้นไม่สามารถมองเห็นได้เพราะมันเปรียบเทียบไบต์ที่แท้จริงของสตริงที่เข้ารหัส หากคุณเปรียบเทียบไบต์จริงของสองสายที่เข้ารหัสโดยใช้อักขระที่แตกต่างกันให้ตั้งค่าสองสายที่ควรพิจารณาเหมือนกันพวกเขาอาจไม่เท่ากัน ตัวอย่างเช่นหากคุณมีคอลัมน์ที่ใช้latin1
ชุดอักขระและชุดอักขระเซิร์ฟเวอร์ / เซสชันของคุณคือutf8mb4
เมื่อคุณเปรียบเทียบคอลัมน์กับสตริงที่มีเครื่องหมายเน้นเสียงเช่น 'café' จะไม่ตรงกับแถวที่มีสตริงเดียวกัน! นี้เป็นเพราะในlatin1
éจะถูกเข้ารหัสเป็นไบต์0xE9
แต่มันเป็นไบต์ที่สอง:utf8
0xC3A9
convert
เช่นกันcollate
?การเรียงหน้าต้องตรงกับชุดอักขระ ดังนั้นถ้าเซิร์ฟเวอร์หรือเซสชั่นของคุณตั้งค่าการใช้latin1
ชุดตัวอักษรที่คุณต้องใช้collate latin1_bin
แต่ถ้าชุดตัวละครของคุณคือคุณต้องใช้utf8mb4
collate utf8mb4_bin
ดังนั้นทางออกที่แข็งแกร่งที่สุดคือการแปลงค่าให้เป็นชุดอักขระที่ยืดหยุ่นที่สุดเสมอและใช้การเปรียบเทียบไบนารีสำหรับชุดอักขระนั้น
convert
และcollate
เพื่อให้มีค่าและไม่คอลัมน์?เมื่อคุณใช้ฟังก์ชันการแปลงใด ๆ กับคอลัมน์ก่อนทำการเปรียบเทียบมันจะป้องกันไม่ให้เอ็นจินการสืบค้นใช้ดัชนีหากมีอยู่สำหรับคอลัมน์ซึ่งอาจทำให้แบบสอบถามของคุณช้าลงอย่างมาก ดังนั้นจึงเป็นการดีกว่าเสมอที่จะเปลี่ยนค่าแทนหากทำได้ เมื่อทำการเปรียบเทียบระหว่างค่าสตริงสองค่าและหนึ่งในนั้นมีการเปรียบเทียบที่ระบุไว้อย่างชัดเจนเอ็นจินการสืบค้นจะใช้การเปรียบเทียบที่ชัดเจนโดยไม่คำนึงถึงค่าที่จะนำไปใช้
มันเป็นสิ่งสำคัญที่จะต้องทราบว่า MySql ไม่เพียง แต่ใช้ตัวพิมพ์เล็กและตัวพิมพ์ใหญ่สำหรับคอลัมน์ที่ใช้การ_ci
เปรียบเทียบ (ซึ่งโดยปกติจะเป็นค่าเริ่มต้น) แต่ยังเน้นเสียงที่ไม่รู้สึกตัว 'é' = 'e'
ซึ่งหมายความว่า การใช้การเปรียบเทียบไบนารี (หรือตัวbinary
ดำเนินการ) จะทำให้การเปรียบเทียบสตริงเน้นความอ่อนไหวและตัวพิมพ์เล็ก
utf8mb4
อะไรutf8
ชุดตัวอักษรใน MySQL เป็นนามแฝงของการutf8mb3
ที่ได้รับการคัดค้านในรุ่นล่าสุดเพราะมันไม่ได้สนับสนุนอักขระไบต์ 4 (ซึ่งเป็นสิ่งสำคัญสำหรับการเข้ารหัสสตริงเช่น🐈) หากคุณต้องการใช้การเข้ารหัสอักขระ UTF8ด้วย MySql คุณควรใช้utf8mb4
ชุดอักขระ
ต่อไปนี้สำหรับ MySQL เวอร์ชันเท่ากับหรือสูงกว่า 5.5
เพิ่มไปยัง /etc/mysql/my.cnf
[mysqld]
...
character-set-server=utf8
collation-server=utf8_bin
...
การเปรียบเทียบอื่น ๆ ทั้งหมดที่ฉันพยายามดูเหมือนจะไม่ตรงตามตัวพิมพ์ใหญ่ - เล็กเฉพาะงาน "utf8_bin"
อย่าลืมรีสตาร์ท mysql หลังจากนี้:
sudo service mysql restart
อ้างอิงจากhttp://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.htmlนอกจากนี้ยังมี "latin1_bin"
"utf8_general_cs" ไม่ได้รับการยอมรับจากการเริ่มต้น mysql (ฉันอ่าน "_cs" ในฐานะ "ตัวพิมพ์เล็ก - ใหญ่" - ???)
คุณสามารถใช้ BINARY เป็นตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ได้
select * from tb_app where BINARY android_package='com.Mtime';
น่าเสียดายที่ sql นี้ไม่สามารถใช้ดัชนีได้คุณจะประสบกับผลการค้นหาคำสั่งที่พึ่งพาดัชนีนั้น
mysql> explain select * from tb_app where BINARY android_package='com.Mtime';
+----+-------------+--------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| 1 | SIMPLE | tb_app | NULL | ALL | NULL | NULL | NULL | NULL | 1590351 | 100.00 | Using where |
+----+-------------+--------+------------+------+---------------+------+---------+------+---------+----------+-------------+
โชคดีที่ฉันมีลูกเล่นเล็กน้อยในการแก้ปัญหานี้
mysql> explain select * from tb_app where android_package='com.Mtime' and BINARY android_package='com.Mtime';
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+
| 1 | SIMPLE | tb_app | NULL | ref | idx_android_pkg | idx_android_pkg | 771 | const | 1 | 100.00 | Using index condition |
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+
ยอดเยี่ยม
ฉันแบ่งปันกับคุณรหัสจากฟังก์ชั่นที่เปรียบเทียบรหัสผ่าน:
SET pSignal =
(SELECT DECODE(r.usignal,'YOURSTRINGKEY') FROM rsw_uds r WHERE r.uname =
in_usdname AND r.uvige = 1);
SET pSuccess =(SELECT in_usdsignal LIKE BINARY pSignal);
IF pSuccess = 1 THEN
/*Your code if match*/
ELSE
/*Your code if don't match*/
END IF;
declare pSuccess BINARY;
เมื่อเริ่มต้น
ไม่จำเป็นต้องเปลี่ยนแปลงอะไรในระดับ DB เพียงคุณต้องเปลี่ยนใน SQL Query มันจะทำงาน
ตัวอย่าง -
"SELECT * FROM <TABLE> where userId = '" + iv_userId + "' AND password = BINARY '" + iv_password + "'";
คำหลักไบนารีจะทำให้ตัวพิมพ์เล็กและตัวพิมพ์ใหญ่
mysql ไม่คำนึงถึงขนาดตัวพิมพ์โดยค่าเริ่มต้นลองเปลี่ยนการจัดเรียงภาษาเป็น latin1_general_cs