MySQL严格字符串比较语义正确的方法?

时间:2016-09-13 08:55:34

标签: mysql string character-encoding

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中严格比较字符串的语义正确的方法是什么?

1 个答案:

答案 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_binCOLLATE gbk_bin