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. データが実際には別の方法でエンコードされている場合、データが 1 つの方法でエンコードされていると考えるのは実際には非常に簡単です。これは、データを直接取得しようとすると、最初にデータベース接続の文字セットに変換され、次に出力メディアの文字セット — したがって、最初に または のいずれSELECT BINARY myColumn FROM myTable WHERE ...かを使用して、格納されたデータの実際のエンコードを確認する必要がありますSELECT HEX(myColumn) FROM myTable WHERE ...

  2. UTF-8 でエンコードされたデータが Windows-1252 でエンコードされた列内に格納されていることを確認したら(つまり0xc39f、文字ßが予期される場所が表示されている場合)、本当に必要なのは、列からエンコード情報を削除し、MySQL にそれを伝えることです。データは実際には UTF-8 としてエンコードされます。ALTER TABLESyntaxの下に記載されているように:

    警告 

    このCONVERT TO操作により、文字セット間で列の値が変換されます。これは、1 つの文字セット ( など) の列があるが、格納された値が実際には別の互換性のない文字セット ( など) を使用している場合には望ましくありません。この場合、そのような列ごとに次の操作を行う必要があります。latin1utf8

    ALTER TABLE t1 CHANGE c1 c1 BLOB;
    ALTER TABLE t1 CHANGE c1 c1 TEXT CHARACTER SET 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 に答える