请透露我有点冗长的回复。
让我们从你的第二个问题开始。%C3%96
表示传输字节0xC3和0x96。这两个字节编码人物Ö以 utf-8 格式 http://www.fileformat.info/info/unicode/char/00d6/index.htm.
由此(并且您的查询产生所描述的结果)我假设您正在使用全程 utf-8 https://stackoverflow.com/questions/279170/utf-8-all-the-way-through.
The 字典顺序 https://en.wikipedia.org/wiki/Lexicographical_ordera 的字符数给定的字符集 http://www.joelonsoftware.com/articles/Unicode.html是由整理 http://dev.mysql.com/doc/refman/5.7/en/charset-literal.html used.
这或多或少是一个有序的字符列表。例如。 A、B、C、D……的含义A<B<C
....
但这些列表可能在同一“位置”包含多个字符,例如
[A,A],B,C,D... 的意思是A==Ä->true
___ 短途旅行,与您的问题不直接相关 ____
我们来看看角色的“名字”Ö
, it's LATIN CAPITAL LETTER O WITH DIAERESIS
.
所以,基本字符是 O,它只是有一些装饰。
某些系统/库允许您指定比较的“粒度”/级别/强度,请参见例如整理者::设置强度 http://docs.php.net/manual/en/collator.setstrength.phpphp-intl 扩展名。
<?php
// utf8 characters
define('SMALL_O_WITH_DIAERESIS', chr(0xC3) . chr(0xB6));
define('CAP_O_WITH_DIAERESIS', chr(0xC3) . chr(0x96));
$coll = collator_create( 'utf-8' );
foreach( array('PRIMARY', 'SECONDARY', 'TERTIARY') as $strength) {
echo $strength, "\r\n";
$coll->setStrength( constant('Collator::'.$strength) );
echo ' o ~ ö = ', $coll->compare('o', SMALL_O_WITH_DIAERESIS), "\r\n";
echo ' Ö ~ ö = ', $coll->compare(CAP_O_WITH_DIAERESIS, SMALL_O_WITH_DIAERESIS), "\r\n";
}
prints
PRIMARY
o ~ ö = 0
Ö ~ ö = 0
SECONDARY
o ~ ö = -1
Ö ~ ö = 0
TERTIARY
o ~ ö = -1
Ö ~ ö = 1
在初级层面上,所有涉及的字符(o,O,ö,Ö)只是字符 O 的一些不相关的变体,因此所有字符都被视为相等。
在二级上,附加的“功能”WITH DIAERESIS
被考虑在内,并且在第三级上还考虑它是小写字母还是大写字母。
但是...MySQL 并不完全是这样工作的...所以,再次抱歉;-)
___ 旅行结束 ____
在 MySQL 中,有指定顺序的排序规则表。当您选择一种字符集时,您还会隐式选择该字符集的默认排序规则,除非您明确指定一种排序规则。在您的情况下,隐式选择的排序规则可能是utf8_general_ci http://collation-charts.org/mysql60/mysql604.utf8_general_ci.european.html它对待 ö==o。
这适用于表定义和连接的字符集/排序规则(后者与您的情况几乎无关)。
另一方面,utf8_turkish_ci 处理 ö!=o。这可能就是您想要的排序规则。
当你有一个像这样的表定义时
CREATE TABLE soFoo (
x varchar(32)
)
CHARACTER SET utf8
选择 utf8 的默认排序规则 -> General_ci -> o=ö
您可以在定义表时指定表的默认排序规则
CREATE TABLE soFoo (
x varchar(32)
)
CHARACTER SET utf8 COLLATE utf8_turkish_ci
由于您已经有一个表和数据,因此您可以更改表的排序规则...但是如果您在表级别执行此操作,则必须使用ALTER TABLE ... CONVERT http://dev.mysql.com/doc/refman/5.7/en/alter-table.html(如果您使用 MODIFY,该列将保留其“原始”排序规则)。
ALTER TABLE soFoo CONVERT TO CHARACTER SET utf8 COLLATE utf8_turkish_ci
这应该可以解决你的问题。
作为旁注,有(如上所述)分配给您的连接的排序规则 https://dev.mysql.com/doc/refman/5.7/en/charset-connection.html以及。选择字符集意味着选择排序规则。我主要用PDO http://docs.php.net/pdo当(直接)连接到 MySQL 时,我的默认连接代码如下所示
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly', array(
PDO::ATTR_EMULATE_PREPARES=>false,
PDO::MYSQL_ATTR_DIRECT_QUERY=>false,
PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION
));
请注意charset=utf8
;没有排序规则,因此再次将 generic_ci 分配给该连接。这就是为什么
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly', array(
PDO::ATTR_EMULATE_PREPARES=>false,
PDO::MYSQL_ATTR_DIRECT_QUERY=>false,
PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION
));
$smallodiaresis_utf8 = chr(0xC3) . chr(0xB6);
foreach( $pdo->query("SELECT 'o'='$smallodiaresis_utf8'") as $row ) {
echo $row[0];
}
prints 1
意思是o==ö。语句中使用的字符串文字被视为 utf8/utf8_general_ci。
我可以在语句中显式指定字符串文字的排序规则
SELECT 'o' COLLATE utf8_turkish_ci ='ö'
(仅将其设置为两个文字/操作数之一;有关其工作原理和原理的信息,请参阅表达式的整理 https://dev.mysql.com/doc/refman/5.7/en/charset-collation-expressions.html)
或者我可以通过设置连接排序规则
$pdo->exec("SET collation_connection='utf8_turkish_ci'");
两者都导致
foreach( $pdo->query("SELECT 'o'[...]='$smallodiaresis_utf8'") as $row ) {
echo $row[0];
}
印刷0
.
编辑:并使事情变得更加复杂:
字符集utf8
不能代表all可能的字符。有更广泛的字符集utf8mb4 https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html.