4

有一个现有的数据库/表,我无法更改字符集。这些表使用排序规则“latin1_swedish_ci”,但其中存储了 UTF-8 数据。例如字符串“fußball”(德国足球)被保存为“fußball”。那是我无法改变的部分。

我的整个脚本与 UTF-8 和它自己的 UTF-8 表一起工作得很好,我使用带有 UTF-8 连接的 PDO(mySQL) 进行查询。但有时我必须查询一些“旧”的 latin1 表。是否有任何“酷”的方法来解决这个问题而不是发送 SET NAMES。

这是我在stackoverflow上的第一个问题!:-)

4

2 回答 2

2
  1. 实际上很容易认为数据是以一种方式编码的,而实际上它是以其他方式编码的:这是因为任何直接检索数据的尝试都会导致首先转换为数据库连接的字符集,然后再转换为输出媒体的字符集——因此您应该首先通过SELECT BINARY myColumn FROM myTable WHERE ...或来验证存储数据的实际编码SELECT HEX(myColumn) FROM myTable WHERE ...

  2. 一旦您确定在 Windows-1252 编码列中存储了 UTF-8 编码数据(即,您正在查看预期0xc39f字符ß的位置),您真正想要的是从列中删除编码信息,然后告诉 MySQL数据实际上被编码为 UTF-8。如ALTER TABLE语法中所述:

    警告 

    CONVERT TO操作在字符集之间转换列值。如果您在一个字符集中有一列(如 ),这不是您想要的,latin1但存储的值实际上使用了其他一些不兼容的字符集(如utf8)。在这种情况下,您必须对每个此类列执行以下操作:

    更改表 t1 更改 c1 c1 BLOB;
    更改表 t1 更改 c1 c1 文本字符集 utf8;
    

    BLOB这样做的原因是当您转换为列或从列转换时没有转换。

  3. 此后,MySQL 将根据需要正确地将所选数据转换为连接字符集的数据。也就是说,如果连接使用 UTF-8,则无需转换;而使用 Windows-1252 的连接将接收转换为该字符集的字符串。

  4. 不仅如此,MySQL 中的字符串比较也会正确执行。例如,如果您当前使用 UTF-8 字符集连接并搜索'fußball',您将不会得到任何结果;而你会在上面的修改之后。

  5. 您提到的必须更改大量遗留脚本的陷阱仅适用于那些遗留脚本使用不正确的连接字符集(例如,告诉 MySQL 他们使用 Windows-1252 而他们实际上正在发送和期待以 UTF-8 格式接收数据)。无论如何,你真的应该解决这个问题,因为它可能会导致各种各样的恐怖。

于 2012-11-29T10:17:04.770 回答
1

我通过在我的 DB 类中创建另一个数据库句柄来解决它,它使用 latin1,所以每当我需要查询“遗留表”时,我可以使用

$pdo    = Db::getInstance();
$pdo->legacyDbh->query("MY QUERY");
# instead of
$pdo->dbh->query("MY QUERY");

如果有人有更好的解决方案,也不要碰桌子.. :-)

于 2012-11-29T10:54:00.197 回答