问题 mysql在utf8_general_ci中区分大小写


我有一个mysql数据库,我使用utf8_general_ci(不区分大小写),在我的表中我有一些像ID这样的列与区分大小写的数据(例如:'iSZ6fX'或'AscSc2')

要将大写字母与小写字母区分开来,最好只在utf8_bin上设置这些列,如下所示:

CREATE TABLE  `test` (
`id` VARCHAR( 32 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL ,
`value1` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL
) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci

或者在所有列上使用utf8_general_ci并在php查询中使用“BINARY”,例如:

mysqli_query( $link, "SELECT * FROM table WHERE BINARY id = 'iSZ6fX'" );

4021
2017-09-11 09:44


起源

是个 数据 区分大小写,或者是单一的 询问 区分大小写?例如,除了那个之外,你通常会做不区分大小写的查询吗?这应该告诉你答案! - Jeremy Smyth


答案:


最好使用 utf8_bin 整理,因为,即使在UTF-8中不可能,在一般情况下理论上可能(例如UTF-16发生) 相同 要表示的字符串 不同 编码,二进制比较不会理解,但二进制校对会。如下所述 Unicode字符集

“按字符的代码值排序”和“按字符的二进制表示排序”之间存在差异,这种差异仅出现在 utf16_bin,因为代理人。

假设 utf16_bin (二进制排序规则 utf16)是一个二进制比较“逐字节”而不是“逐个字符。”如果是这样,字符的顺序 utf16_bin 会与订单不同 utf8_bin。例如,下图显示了两个罕见的字符。第一个字符在范围内 E000-FFFF,所以它大于代理人但不足以补充。第二个字符是补充。

代码点字符utf8 utf16
---------- --------- ---- -----
0FF9D HALFWIDTH KATAKANA LETTER N EF BE 9D FF 9D
10384 UGARITIC LETTER DELTA F0 90 8E 84 D8 00 DF 84

图表中的两个字符按代码点值排序,因为 0xff9d < 0x10384。它们是按顺序排列的 utf8 价值因为 0xef < 0xf0。但他们并没有按顺序排列 utf16 值,如果我们使用逐字节比较,因为 0xff > 0xd8

所以MySQL的 utf16_bin 整理不是“逐字节”。它是“按代码点。”当MySQL看到一个补充字符编码 utf16,它转换为角色的代码点值,然后进行比较。因此, utf8_bin 和 utf16_bin 是相同的顺序。这与UCS_BASIC排序规则的SQL:2008标准要求一致:“UCS_BASIC是一种排序规则,其排序完全取决于要排序的字符串中字符的Unicode标量值。它适用于UCS角色曲目。由于每个字符集都是UCS指令集的子集,因此UCS_BASIC校对可能适用于每个字符集。注11:字符的Unicode标量值是其代码点,被视为无符号整数。“

因此,如果涉及这些列的比较将会 总是 区分大小写,您应该将列的排序规则设置为 utf8_bin (即使您忘记在查询中另行指定,它们仍将保持区分大小写);或者如果只有特定查询区分大小写,您可以指定 utf8_bin应该使用排序规则 COLLATE 关键词:

SELECT * FROM table WHERE id = 'iSZ6fX' COLLATE utf8_bin

13
2017-09-11 09:56



所以,如果我总是需要区分大小写的数据,最好设置 utf8_bin 仅在此列中,并在所有其他列中以及表和数据库utf8_general_ci中保留utf8_general_ci。否则,如果只有少数查询区分大小写,则只需添加 收集utf8_bin 在查询中,即使列排序规则是utf8_general_ci。那是对的吗? - ipel
@ipel:是的,这是正确的。 - eggyal


最好使用带有'utf8_bin'的列而不是在查询中指定条件,因为它可以减少出错的可能性。


1
2017-09-11 09:52



您能举例说明可能发生的错误吗? - eggyal


BINARY作为列属性的效果不同于它在MySQL 4.1之前的效果。以前,BINARY导致一个被视为二进制字符串的列。二进制字符串是没有字符集或排序规则的字节字符串,它与具有二进制排序规则的非二进制字符串不同。

但现在

BINARY运算符将其后面的字符串转换为二进制字符串。这是一种简单的方法,可以逐个字节而不是逐个字符地强制进行比较。 BINARY也会导致尾随空格显着。 BINARY str是CAST的简写(str AS BINARY)。

字符列定义中的BINARY属性具有不同的效果。使用BINARY属性定义的字符列将分配列字符集的二进制排序规则。每个字符集都有一个二进制排序规则。例如,latin1字符集的二进制排序规则是latin1_bin,因此如果表默认字符集是latin1,则这两个列定义是等效的:

CHAR(10) BINARY

CHAR(10) CHARACTER SET latin1 COLLATE latin1_bin

0
2017-09-11 09:53