Tôi có một hàm trả về năm ký tự với trường hợp hỗn hợp. Nếu tôi thực hiện một truy vấn trên chuỗi này, nó sẽ trả về giá trị bất kể trường hợp nào.
Làm thế nào tôi có thể làm cho trường hợp truy vấn chuỗi MySQL nhạy cảm?
Tôi có một hàm trả về năm ký tự với trường hợp hỗn hợp. Nếu tôi thực hiện một truy vấn trên chuỗi này, nó sẽ trả về giá trị bất kể trường hợp nào.
Làm thế nào tôi có thể làm cho trường hợp truy vấn chuỗi MySQL nhạy cảm?
Câu trả lời:
http://dev.mysql.com/doc/refman/5.0/en/case-sensergy.html
Bộ ký tự và đối chiếu mặc định là latin1 và latin1_swbur_ci, do đó, so sánh chuỗi không phân biệt là trường hợp không phân biệt theo mặc định. Điều này có nghĩa là nếu bạn tìm kiếm bằng col_name THÍCH 'a%', bạn sẽ nhận được tất cả các giá trị cột bắt đầu bằng A hoặc a. Để làm cho trường hợp tìm kiếm này nhạy cảm, hãy đảm bảo rằng một trong các toán hạng có đối chiếu trường hợp nhạy cảm hoặc nhị phân. Ví dụ: nếu bạn đang so sánh một cột và một chuỗi có cả bộ ký tự latin1, bạn có thể sử dụng toán tử COLLATE để làm cho toán hạng có đối chiếu latin1_general_cs hoặc 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
Nếu bạn muốn một cột luôn được xử lý theo kiểu phân biệt chữ hoa chữ thường, hãy khai báo nó với một đối chiếu nhị phân hoặc phân biệt chữ hoa chữ thường.
SELECT 'email' COLLATE utf8_bin = 'Email'
Tin tốt là nếu bạn cần thực hiện một truy vấn phân biệt chữ hoa chữ thường, thì rất dễ thực hiện:
SELECT * FROM `table` WHERE BINARY `column` = 'value'
convert(char(0x65,0xcc,0x88) using utf8)
(nghĩa là e
có ¨
thêm) và convert(char(0xc3,0xab) using utf8)
(nghĩa là ë
), nhưng việc thêm BINARY
sẽ làm cho chúng không bằng nhau.
Trả lời được đăng bởi Craig White, có hiệu suất phạt lớn
SELECT * FROM `table` WHERE BINARY `column` = 'value'
bởi vì nó không sử dụng chỉ mục. Vì vậy, hoặc bạn cần thay đổi đối chiếu bảng như được đề cập ở đây https://dev.mysql.com/doc/refman/5.7/en/case-sens nhạy.html .
HOẶC LÀ
Sửa chữa dễ nhất, bạn nên sử dụng một giá trị BINary.
SELECT * FROM `table` WHERE `column` = BINARY 'value'
Ví dụ.
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 hàng trong bộ (0,00 giây)
Thay vì sử dụng toán tử =, bạn có thể muốn sử dụng THÍCH hoặc THÍCH 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'
Nó sẽ mất 'a' chứ không phải 'A' trong điều kiện của nó
Để sử dụng một chỉ mục trước khi sử dụng BINary, bạn có thể làm một cái gì đó như thế này nếu bạn có các bảng lớn.
SELECT
*
FROM
(SELECT * FROM `table` WHERE `column` = 'value') as firstresult
WHERE
BINARY `column` = 'value'
Truy vấn con sẽ dẫn đến một tập hợp con không phân biệt chữ hoa chữ thường rất nhỏ mà sau đó bạn chọn đối sánh phân biệt chữ hoa chữ thường.
Cách chính xác nhất để thực hiện so sánh chuỗi phân biệt chữ hoa chữ thường mà không thay đổi đối chiếu của cột được truy vấn là chỉ định rõ ràng một bộ ký tự và đối chiếu cho giá trị mà cột đang được so sánh.
select * from `table` where `column` = convert('value' using utf8mb4) collate utf8mb4_bin;
binary
?Việc sử dụng binary
toán tử là không thể vì nó so sánh các byte thực tế của các chuỗi được mã hóa. Nếu bạn so sánh các byte thực tế của hai chuỗi được mã hóa bằng cách sử dụng các ký tự khác nhau thì hai chuỗi nên được coi là giống nhau, chúng có thể không bằng nhau. Ví dụ: nếu bạn có một cột sử dụng bộ latin1
ký tự và bộ ký tự máy chủ / phiên của bạn là utf8mb4
, thì khi bạn so sánh cột với một chuỗi có dấu như 'café', nó sẽ không khớp với các hàng có cùng chuỗi đó! Điều này là do trong latin1
é được mã hóa dưới dạng byte 0xE9
nhưng trong utf8
đó là hai byte : 0xC3A9
.
convert
tốt như collate
?Bộ sưu tập phải phù hợp với bộ ký tự. Vì vậy, nếu máy chủ hoặc phiên của bạn được đặt để sử dụng bộ latin1
ký tự bạn phải sử dụng collate latin1_bin
nhưng nếu bộ ký tự của bạn là utf8mb4
bạn phải sử dụng collate utf8mb4_bin
. Do đó, giải pháp mạnh mẽ nhất là luôn chuyển đổi giá trị thành bộ ký tự linh hoạt nhất và sử dụng đối chiếu nhị phân cho bộ ký tự đó.
convert
và collate
cho giá trị mà không phải cột?Khi bạn áp dụng bất kỳ chức năng chuyển đổi nào cho một cột trước khi thực hiện so sánh, nó sẽ ngăn công cụ truy vấn sử dụng một chỉ mục nếu có tồn tại cho cột, điều này có thể làm chậm đáng kể truy vấn của bạn. Do đó, luôn luôn tốt hơn để chuyển đổi giá trị thay vì có thể. Khi so sánh được thực hiện giữa hai giá trị chuỗi và một trong số chúng có đối chiếu được chỉ định rõ ràng, công cụ truy vấn sẽ sử dụng đối chiếu rõ ràng, bất kể giá trị nào được áp dụng.
Điều quan trọng cần lưu ý là MySql không chỉ không phân biệt chữ hoa chữ thường đối với các cột bằng cách sử dụng _ci
đối chiếu (thường là mặc định), mà còn không có dấu không nhạy. Điều này có nghĩa là 'é' = 'e'
. Sử dụng đối chiếu nhị phân (hoặc binary
toán tử) sẽ làm cho các phép so sánh chuỗi có độ nhạy cũng như phân biệt chữ hoa chữ thường.
utf8mb4
gìBộ utf8
ký tự trong MySql là một bí danh utf8mb3
đã bị phản đối trong các phiên bản gần đây vì nó không hỗ trợ các ký tự 4 byte (rất quan trọng đối với các chuỗi mã hóa như). Nếu bạn muốn sử dụng mã hóa ký tự UTF8 với MySql thì bạn nên sử dụng bộ utf8mb4
ký tự.
Sau đây là cho các phiên bản MySQL bằng hoặc cao hơn 5,5.
Thêm vào /etc/mysql/my.cnf
[mysqld]
...
character-set-server=utf8
collation-server=utf8_bin
...
Tất cả các bộ sưu tập khác mà tôi đã thử dường như không phân biệt chữ hoa chữ thường, chỉ có "utf8_bin" hoạt động.
Đừng quên khởi động lại mysql sau này:
sudo service mysql restart
Theo http://dev.mysql.com/doc/refman/5.0/en/case-sens nhạy.html cũng có một "latin1_bin".
"Utf8_general_cs" không được chấp nhận bởi khởi động mysql. (Tôi đọc "_cs" là "phân biệt chữ hoa chữ thường" - ???).
Bạn có thể sử dụng BINary cho trường hợp nhạy cảm như thế này
select * from tb_app where BINARY android_package='com.Mtime';
Thật không may, sql này không thể sử dụng chỉ mục, bạn sẽ bị ảnh hưởng bởi các truy vấn phụ thuộc vào chỉ mục đó
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 |
+----+-------------+--------+------------+------+---------------+------+---------+------+---------+----------+-------------+
May mắn thay, tôi có một vài thủ thuật để giải quyết vấn đề này
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 |
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+
Thông minh!
Tôi chia sẻ với bạn, mã từ một chức năng so sánh mật khẩu:
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;
vào lúc bắt đầu
Không cần thay đổi bất cứ điều gì ở cấp độ DB, chỉ cần bạn phải thay đổi trong Truy vấn SQL thì nó sẽ hoạt động.
Thí dụ -
"SELECT * FROM <TABLE> where userId = '" + iv_userId + "' AND password = BINARY '" + iv_password + "'";
Từ khóa nhị phân sẽ làm cho trường hợp nhạy cảm.