The **compare-on-binary way** is **NOT semantically-correct**
例如,当你想用不同的编码字符串进行 strict-string-comparison 时,就会出现比较二进制方式的错误。以下测试用例说明了原因:
在这种情况下,我想将字段'北京 '
中的字符串城市
(带有填充空格)替换为字符串'北京111'
,但保持字符串'北京'
不变,所以我写下以下的sql:
SELECT CASE WHEN BINARY `城市` = BINARY '北京 ' THEN '北京111' ELSE `城市` END
FROM `中文测试表1`
GROUP BY BINARY CASE WHEN BINARY `城市` = BINARY '北京 ' THEN '北京111' ELSE `城市` END
基础表定义和数据(会话编码设置为'utf8mb4'):
CREATE TABLE `中文测试表1` (
`城市` varchar(50) CHARACTER SET gbk DEFAULT NULL,
`销量` int(11) DEFAULT NULL
) ENGINE=InnoDB;
INSERT INTO `中文测试表1` VALUES ('杭州', '111');
INSERT INTO `中文测试表1` VALUES ('北京', '345');
INSERT INTO `中文测试表1` VALUES ('北京 ', '123');
实际发生的是字符串'北京 '
未被'北京111'
取代,并且仍然保留了结果集中的内容。
原因是,字符串文字'北京 '
使用utf8mb4编码(由会话决定),字段'北京 '
的字符串值城市
使用gbk编码(这是由表定义决定),当它们被转换为二进制时,它们的每个字节都不相同,但是两个字符串在每个字符上确实在语义上相等(无论使用什么底层编码方法)。
那么,在MySQL中严格比较字符串的语义正确的方法是什么?
答案 0 :(得分:0)
请参阅TRIM()
函数以从字符串的开头/结尾删除空格。
在gbk和utf8mb4之间进行转换会让您受到转换表的支配;你可能(或可能不)获得所需的音译。
对于utf8 / utf8mb4, '北京'
为HEX E58C97 E4BAAC
对于utf8 / utf8mb4,'北京 '
是HEX E58C97 E4BAAC 20
- 如查询中所示
对于gbk,'北京'
是HEX B1B1 BEA9
对于gbk,'北京 '
是HEX B1B1 BEA9 20
- 如表
当您说SELECT ... BINARY '北京 ' ...
时,字符串的编码基于连接,而不是列编码。所以它是utf8mb4。
而不是... WHEN BINARY 城市 = BINARY '北京 ' THEN ...
,请执行以下操作之一:
计划A,让转化自动发生:... WHEN 城市 = '北京 ' THEN ...
计划B,明确转换:... WHEN 城市 = CONVERT('北京 ' USING gbk) THEN ...
计划C,使用HEX:... WHEN HEX(城市) = HEX(CONVERT('北京 ' USING gbk)) THEN ...
计划D,更接近您的尝试:... WHEN BINARY 城市 = BINARY(CONVERT('北京 ' USING gbk)) THEN ...
还有其他方法,使用COLLATE utf8_bin
,COLLATE gbk_bin
等