2016-12-14 20 views
15

Hãy giúp tôi hiểu các ký tự đa byte như biểu tượng cảm xúc được xử lý trong các trường MySQL utf8mb4 như thế nào.Tôi làm cách nào để tìm kiếm bằng biểu tượng cảm xúc trong MySQL bằng utf8mb4?

Xem bên dưới để biết SQL thử nghiệm đơn giản để minh họa các thách thức.

/* Clear Previous Test */ 
DROP TABLE IF EXISTS `emoji_test`; 
DROP TABLE IF EXISTS `emoji_test_with_unique_key`; 

/* Build Schema */ 
CREATE TABLE `emoji_test` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `string` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', 
    `status` tinyint(1) NOT NULL DEFAULT '1', 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 
CREATE TABLE `emoji_test_with_unique_key` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `string` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', 
    `status` tinyint(1) NOT NULL DEFAULT '1', 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `idx_string_status` (`string`,`status`) USING BTREE 
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 

/* INSERT data */ 
# Expected Result is successful insert for each of these. 
# However some fail. See comments. 
INSERT INTO emoji_test (`string`, `status`) VALUES ('', 1);     # SUCCESS 
INSERT INTO emoji_test (`string`, `status`) VALUES ('', 1);     # SUCCESS 
INSERT INTO emoji_test (`string`, `status`) VALUES ('', 1);     # SUCCESS 
INSERT INTO emoji_test (`string`, `status`) VALUES ('', 1);     # SUCCESS 
INSERT INTO emoji_test_with_unique_key (`string`, `status`) VALUES ('', 1); # SUCCESS 
INSERT INTO emoji_test_with_unique_key (`string`, `status`) VALUES ('', 1); # FAIL: Duplicate entry '?-1' for key 'idx_string_status' 
INSERT INTO emoji_test_with_unique_key (`string`, `status`) VALUES ('', 1); # SUCCESS 
INSERT INTO emoji_test_with_unique_key (`string`, `status`) VALUES ('', 1); # FAIL: Duplicate entry '??-1' for key 'idx_string_status' 

/* Test data */ 

    /* Simple Table */ 
SELECT * FROM emoji_test WHERE `string` IN ('','','',''); # SUCCESS (all 4 are found) 
SELECT * FROM emoji_test WHERE `string` IN ('');      # FAIL: Returns both and 
SELECT * FROM emoji_test WHERE `string` IN ('');      # FAIL: Returns both and 
SELECT * FROM emoji_test;            # SUCCESS (all 4 are found) 

    /* Table with Unique Key */ 
SELECT * FROM emoji_test_with_unique_key WHERE `string` IN ('','','',''); # FAIL: Only 2 are found (due to insert errors above) 
SELECT * FROM emoji_test_with_unique_key WHERE `string` IN ('');      # SUCCESS 
SELECT * FROM emoji_test_with_unique_key WHERE `string` IN ('');      # FAIL: found instead of 
SELECT * FROM emoji_test_with_unique_key;            # FAIL: Only 2 records found (and) 

Tôi quan tâm đến việc học những gì gây ra FAIL s trên và làm thế nào tôi có thể làm được việc này.

Cụ thể:

  1. Tại sao Selects cho một multibyte kết quả nhân vật để đổi lấy bất kỳ ký tự multibyte?
  2. Tôi làm cách nào để định cấu hình chỉ mục để xử lý các ký tự nhiều byte thay vì ??
  3. Bạn có thể đề xuất các thay đổi cho số CREATE TABLE thứ hai (khóa có khóa duy nhất) ở trên theo cách làm cho tất cả các truy vấn kiểm tra trở lại thành công không?
+4

Như bất kỳ người Mexico có thể cho bạn biết, ([ 'TACO' (U + 1F32E)] (http://www.fileformat.info/info/unicode/char/1f32e/index.htm)) và ([ 'HOT PEPPER '(U + 1F336)] (http://www.fileformat.info/info/unicode/char/1f336/index.htm)) có liên quan rõ ràng nhưng khác nhau. Đây phải là câu hỏi được sáng tác tuyệt vời nhất trong nhiều năm. –

+0

liên quan: http://stackoverflow.com/questions/38116984/finding-values-case-insensitively-with-emojis: * Giải pháp là sử dụng MySQL 5.6+ và sử dụng utf8mb4_unicode_520_ci chiếu mà không đối xử với tất cả 4 ký tự byte như bình đẳng * - một lý do khá tốt để tránh biểu tượng cảm xúc như mật khẩu :) –

+1

@ ÁlvaroGonzález Vâng, nếu đây là một vấn đề đối với mật khẩu, sau đó có một vấn đề lớn hơn lớn hơn với các thiết lập nhất định, vì các mật khẩu được lưu trữ với một hash oneway. Và vì băm, nó không phải là một vấn đề. Nhưng tôi cũng sẽ không gợi ý sử dụng chúng cho mật khẩu. –

Trả lời

11

Bạn sử dụng utf8mb4_unicode_ci cho các cột của mình, vì vậy séc không phân biệt chữ hoa chữ thường. Thay vào đó, nếu bạn sử dụng utf8mb4_bin, thì biểu tượng cảm xúc và được xác định chính xác là các chữ cái khác nhau.

Với WEIGHT_STRING bạn có thể nhận được các giá trị được sử dụng để sắp xếp và so sánh cho chuỗi đầu vào.

Nếu bạn viết:

SELECT 
    WEIGHT_STRING ('' COLLATE 'utf8mb4_unicode_ci'), 
    WEIGHT_STRING ('' COLLATE 'utf8mb4_unicode_ci') 

Sau đó, bạn có thể thấy rằng cả hai đều là 0xfffd. Trong số Unicode Character Sets họ nói:

Đối với các ký tự bổ sung trong collations chung, trọng số là trọng số cho 0xfffd THAY THẾ CHARACTER.

Nếu bạn viết:

SELECT 
    WEIGHT_STRING('' COLLATE 'utf8mb4_bin'), 
    WEIGHT_STRING('' COLLATE 'utf8mb4_bin') 

Bạn sẽ nhận được unicode họ đánh giá cao 0x01f32e0x01f336 để thay thế.

Đối với các chữ cái khác như Ä, ÁA rằng đều bình đẳng nếu bạn sử dụng utf8mb4_unicode_ci, sự khác biệt có thể được nhìn thấy trong:

SELECT 
    WEIGHT_STRING ('Ä' COLLATE 'utf8mb4_unicode_ci'), 
    WEIGHT_STRING ('A' COLLATE 'utf8mb4_unicode_ci') 

Những bản đồ để đến trọng lượng 0x0E33

Ä: 00C4 ; [.0E33.0020.0008.0041][.0000.0047.0002.0308] # LATIN CAPITAL LETTER A WITH DIAERESIS; QQCM 
A: 0041 ; [.0E33.0020.0008.0041] # LATIN CAPITAL LETTER A 

Theo để: Difference between utf8mb4_unicode_ci and utf8mb4_unicode_520_ci collations in MariaDB/MySQL? trọng lượng sử dụng cho utf8mb4_unicode_ci được dựa trên UCA 4.0.0 vì biểu tượng cảm xúc không xuất hiện trong đó, ánh xạ chúng tôi ight là 0xfffd

Nếu bạn cần phân biệt dạng chữ so sánh và loại cho thư thường xuyên cùng với biểu tượng cảm xúc thì vấn đề này được giải quyết bằng utf8mb4_unicode_520_ci:

SELECT 
    WEIGHT_STRING('' COLLATE 'utf8mb4_unicode_520_ci'), 
    WEIGHT_STRING('' COLLATE 'utf8mb4_unicode_520_ci') 

có cũng sẽ nhận được trọng lượng khác nhau đối với những biểu tượng cảm xúc 0xfbc3f32e0xfbc3f336.

+0

Điều này thật đáng kinh ngạc. Chuyển đổi mã hóa thành 'utf8mb4_bin' trong' TÊN TẠO 'ở trên đã làm cho phần còn lại của các truy vấn kiểm tra hoạt động chính xác như mong đợi. Cám ơn rất nhiều. Mọi thông tin chi tiết hơn về điều này sẽ được đánh giá cao. – Ryan

+1

Không ngạc nhiên đối chiếu nhị phân sửa chữa vấn đề này (đó là những gì nó có nghĩa là cho) nhưng tôi không thể hiểu tại sao hai biểu tượng cảm xúc hoàn toàn khác nhau sẽ được coi là trường hợp biến thể của cùng một ký tự. Tôi nghi ngờ nó là cố ý. –

+0

@ ÁlvaroGonzález một lý do tương tự như lý do tại sao 'a', 'a' và' A' đều giống nhau, ngay cả khi họ có thể có cách phát âm khác nhau và ý nghĩa. Mặc dù vậy, điều đầu tiên của tôi là, chúng được đối xử bình đẳng, bởi vì chúng đều thuộc loại thực phẩm, nhưng nhiều khả năng là 'ci' chỉ kiểm tra nếu chúng là biểu tượng cảm xúc. –

Các vấn đề liên quan