I've a mysql database where i use utf8_general_ci (that is case insensitive), and in my tables i have some columns like ID with case-sensitive data (example: 'iSZ6fX' or 'AscSc2')
To distinct uppercase from lowercase is better to set on these columns only the utf8_bin, like this:
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
Or use utf8_general_ci on all columns and use 'BINARY' in the php query, for example:
mysqli_query( $link, "SELECT * FROM table WHERE BINARY id = 'iSZ6fX'" );
It is better to use the utf8_bin
collation because, even though it is not possible in UTF-8, in the general case it is theoretically possible (such as happens with UTF-16) for the same string to be represented by different encodings, which a binary comparison would not understand but a binary collation would. As documented under Unicode Character Sets:
There is a difference between “ordering by the character's code value” and “ordering by the character's binary representation,” a difference that appears only with
utf16_bin
, because of surrogates.Suppose that
utf16_bin
(the binary collation forutf16
) was a binary comparison “byte by byte” rather than “character by character.” If that were so, the order of characters inutf16_bin
would differ from the order inutf8_bin
. For example, the following chart shows two rare characters. The first character is in the rangeE000-FFFF
, so it is greater than a surrogate but less than a supplementary. The second character is a supplementary.Code point Character utf8 utf16 ---------- --------- ---- ----- 0FF9D HALFWIDTH KATAKANA LETTER N EF BE 9D FF 9D 10384 UGARITIC LETTER DELTA F0 90 8E 84 D8 00 DF 84The two characters in the chart are in order by code point value because
0xff9d
<0x10384
. And they are in order byutf8
value because0xef
<0xf0
. But they are not in order byutf16
value, if we use byte-by-byte comparison, because0xff
>0xd8
.So MySQL's
utf16_bin
collation is not “byte by byte.” It is “by code point.” When MySQL sees a supplementary-character encoding inutf16
, it converts to the character's code-point value, and then compares. Therefore,utf8_bin
andutf16_bin
are the same ordering. This is consistent with the SQL:2008 standard requirement for a UCS_BASIC collation: “UCS_BASIC is a collation in which the ordering is determined entirely by the Unicode scalar values of the characters in the strings being sorted. It is applicable to the UCS character repertoire. Since every character repertoire is a subset of the UCS repertoire, the UCS_BASIC collation is potentially applicable to every character set. NOTE 11: The Unicode scalar value of a character is its code point treated as an unsigned integer.”
Therefore, if comparisons involving these columns will always be case-sensitive, you should set the column's collation to utf8_bin
(so that they will remain case sensitive even if you forget to specify otherwise in your query); or if only particular queries are case-sensitive, you could specify that the utf8_bin
collation should be used using the COLLATE
keyword:
SELECT * FROM table WHERE id = 'iSZ6fX' COLLATE utf8_bin