mysqlの「不正な照合順序の組み合わせ」エラーのトラブルシューティング


210

MySQLのストアドプロシージャを使用して選択しようとすると、以下のエラーが発生します。

オペレーション '='の照合(latin1_general_cs、IMPLICIT)と(latin1_general_ci、IMPLICIT)の不正な組み合わせ

ここで何がうまくいかないのかについて何か考えはありますか?

テーブルの照合順序はlatin1_general_ciであり、where句の列の照合順序はlatin1_general_csです。


2
私は長い間(1990年以降)さまざまなデータベースを使用しており、NySQLによって行われた照合と保磁力の使用法は「クレイジー」であるように見え、データベースはデータベースに「ONE」文字セットを課す問題を解決し、その後データベースで使用される一意の文字セットとの間で変換を行うためのインポート/エクスポート手順 「アプリケーションの問題」(文字セットの変換)とデータベースの問題(照合順序の使用)が混在しているため、Mysqlが選択したソリューションは混乱を招くものです。なぜ「削除」データベースから愚かと面倒な特徴は、それがでずっと使えると制御可能になっていること
マウリツィオPievaioli

回答:


216

これは通常、互換性のない照合の2つの文字列を比較するか、異なる照合のデータを組み合わせて1つの列に選択しようとしたことが原因です。

この句をCOLLATE使用すると、クエリで使用する照合を指定できます。

たとえば、次のWHERE句では常に投稿したエラーが表示されます。

WHERE 'A' COLLATE latin1_general_ci = 'A' COLLATE latin1_general_cs

解決策は、クエリ内の2つの列に共有照合を指定することです。COLLATE句を使用する例を次に示します。

SELECT * FROM table ORDER BY key COLLATE latin1_general_ci;

別のオプションは、BINARY演算子を使用することです:

BINARY strはCAST(str AS BINARY)の省略形です。

ソリューションは次のようになります。

SELECT * FROM table WHERE BINARY a = BINARY b;

または、

SELECT * FROM table ORDER BY BINARY a;

2
ありがとう。実際、私の場合はかなり奇妙な動作をしているようです。クエリをそのまま実行すると、クエリブラウザを介して結果が取得されます。ただし、ストアドプロシージャを使用するとエラーがスローされます。
user355562 2010年

5
バイナリは私にとって最良の解決策のようでした。トリッキーなフィルターを使用していないのであれば、それはあなたにとってもベストかもしれません。
Adam F

同じ問題があります。この問題を解決する方法は、最初から作り直します。照合順序を変更しようとしましたが、joinを実行してもエラーが発生するので、そのようにしてみました。cmiiw
ボビーZ

MariaDBの使用COLLATE latin1_general_ci には別のエラーの原因となるバグがあることに注意してください :COLLATION 'utf8_general_ci' is not valid for CHARACTER SET 'latin1''-CHARACTER SET 'latin1'の列がない場合でも!解決策は、BINARYキャストを使用することです。この質問
Mel_T

154

TL; DR

文字列の1つ(または両方)の照合を変更して一致するようにするかCOLLATE、式に句を追加します。


  1. とにかく、この「照合」のものは何ですか?

    一般に文字セットと照合順序で説明されているように:

    文字セットは、シンボルとエンコーディングのセットです。照合は、文字セット内の文字を比較するためのルールのセットです。架空の文字セットの例を使用して、区別を明確にしましょう。

    A」、「B」、「a」、「b」の4文字のアルファベットがあるとします。各文字に番号を付けます:「A」= 0、「B」= 1、「a」= 2、「b」=3。文字「A」は記号、数字0は「」のエンコーディングA、およびすべての組み合わせ4つの文字とそのエンコーディングは文字セットです。

    2つの文字列値「A」と「B」を比較するとします。これを行う最も簡単な方法は、エンコーディングを確認することです。「A」は0、「」は1ですB。0は1より小さいため、「A」は「」より小さいと言いBます。先ほど行ったのは、文字セットに照合を適用することです。照合は一連のルール(この場合は1つのルールのみ)です:「エンコードを比較します」。考えられるすべての照合のうち最も単純なものをバイナリ照合と呼びます。

    しかし、小文字と大文字が同等であると言いたい場合はどうでしょうか?その後、我々は、少なくとも二つのルールがあります:(1)は、「小文字の治療a」と「b」「に相当するとA」と「B」。(2)次に、エンコーディングを比較します。これを大文字と小文字を区別しない照合と呼びます。バイナリ照合よりも少し複雑です。

    現実には、ほとんどの文字セットには多くの文字があります。「A」と「B」だけでなく、アルファベット全体、時には数千の文字を含む複数のアルファベットまたは東洋の書記体系、および多くの特殊記号と句読点があります。また、実際には、ほとんどの照合には、大文字と小文字を区別するかどうかだけでなく、アクセント(「アクセント」はドイツ語の「Ö」のように文字に付けられたマークです)を区別するかどうか、および複数の文字に関する多くのルールがあります。マッピング(2つのドイツ語照合のうちの1つで「Ö」=「OE」というルールなど)。

    さらなる例は、照合の影響の例に示されています。

  2. さて、しかし、MySQLは与えられた式に使用する照合をどのように決定するのでしょうか?

    式の照合に記載されているように:

    ほとんどのステートメントでは、比較操作を解決するためにMySQLが使用する照合順序は明らかです。たとえば、次の場合、照合順序がcolumnの照合順序であることは明らかですcharset_name

    SELECT x FROM T ORDER BY x;
    SELECT x FROM T WHERE x = x;
    SELECT DISTINCT x FROM T;

    ただし、複数のオペランドがあると、あいまいになる可能性があります。例えば:

    SELECT x FROM T WHERE x = 'Y';

    比較では、列xまたは文字列リテラルの照合を使用する必要があります'Y'か?どちらx'Y'照合順序を持っているので、その照合が優先されますか?

    標準SQLは、「強制力」ルールと呼ばれていたものを使用して、このような質問を解決します。

    [ 削除 ]

    MySQLは、あいまいさを解決するために、次のルールで強制可能性値を使用します。

    • 最小の強制可能性値を持つ照合を使用します。

    • 両方の保磁力が同じ場合、次のようになります。

      • 両側がUnicodeの場合、または両側がUnicodeでない場合は、エラーです。

      • 一方の側にUnicode文字セットがあり、もう一方の側に非Unicode文字セットがある場合、Unicode文字セットを持つ側が優先され、自動文字セット変換が非Unicode側に適用されます。たとえば、次のステートメントはエラーを返しません。

        SELECT CONCAT(utf8_column, latin1_column) FROM t1;

        の文字セットとutf8と同じ照合順序を持つ結果を返しますutf8_column。の値は、連結latin1_columnするutf8前に自動的にに変換されます。

      • 同じ文字セットのオペランドを使用するが、_bin照合と_cior _cs照合が混在する演算の場合、_bin照合が使用されます。これは、非バイナリ文字列とバイナリ文字列を混在させる操作が、オペランドをバイナリ文字列として評価する方法と似ていますが、データ型ではなく照合順序である点が異なります。

  3. では、「照合の違法な組み合わせ」とは何でしょうか。

    「照合の違法な組み合わせ」は、式が異なる照合の2つの文字列を比較するが、保磁力は等しい場合に発生し、保磁力のルールは競合の解決に役立ちません。これは、上記の引用の3番目の箇条書きで説明されている状況です。

    質問で与えられた特定のエラーIllegal mix of collations (latin1_general_cs,IMPLICIT) and (latin1_general_ci,IMPLICIT) for operation '='は、等しい保磁力の2つの非Unicode文字列の間に等しい比較があったことを示しています。さらに、照合順序はステートメントで明示的に指定されたのではなく、文字列のソース(列のメタデータなど)から暗示されていたことがわかります。

  4. それはすべて非常にうまくいきますが、そのようなエラーをどのように解決しますか?

    上記で引用したマニュアルの抜粋が示唆するように、この問題はいくつかの方法で解決できます。そのうちの2つは賢明であり、推奨されます。

    • ストリングの1つ(または両方)の照合を変更して、ストリングが一致し、あいまいさがなくなるようにします。

      これを行う方法は、文字列がどこから来たかによって異なります。リテラル式は、collation_connectionシステム変数で指定された照合を受け取ります。テーブルの値は、列のメタデータで指定された照合順序を取ります。

    • 1つの文字列を強制できないようにします。

      上記から次の引用を省略しました:

      MySQLは、次のように強制可能性の値を割り当てます。

      • 明示的なCOLLATE句の強制力は0です(強制力はまったくありません)。

      • 照合順序が異なる2つの文字列を連結すると、強制力は1になります。

      • 列またはストアドルーチンのパラメーターまたはローカル変数の照合には、強制力2があります。

      • 「システム定数」(USER()またはなどの関数によって返される文字列VERSION())の保磁力は3です。

      • リテラルの照合には、強制力4があります。

      • NULLまたは、派生した式NULLの保磁力は5です。

      したがってCOLLATE、比較で使用される文字列の1つに句を追加するだけで、その照合が強制的に使用されます。

    他の人がこのエラーを解決するためだけに配備された場合、ひどく悪い習慣になりますが、

    • 文字列の一方(または両方)に強制的に他の強制力の値を設定して、一方が優先されるようにします。

      CONCAT()またはCONCAT_WS()を使用すると、強制力1の文字列になります。(ストアドルーチン内にある場合)パラメータ/ローカル変数を使用すると、強制力が2の文字列になります。

    • 文字列の一方(または両方)のエンコーディングを変更して、一方がUnicodeになり、もう一方がUnicodeにならないようにします。

      これは、を使用したトランスコーディングによって行うことができます。または、データの基礎となる文字セットを変更する(たとえば、列の変更、リテラル値の変更、またはクライアントからの異なるエンコーディングでの送信、および文字セットイントロデューサの変更/追加)。新しい文字セットで目的の文字をエンコードできない場合、エンコードを変更すると他の問題が発生することに注意してください。CONVERT(expr USING transcoding_name)character_set_connectioncharacter_set_client

    • 文字列の一方(または両方)のエンコーディングを変更して両方が同じになるようにし、1つの文字列を変更して関連する_bin照合を使用するようにします。

      エンコーディングと照合順序を変更する方法については、上記で詳しく説明しています。照合によって提供されるよりも高度な照合ルールを実際に適用する必要がある場合、このアプローチはほとんど役に立ちません_bin


4
「照合の不正な組み合わせ」は、どの照合を使用するべきか曖昧さがない場合にも発生する可能性がありますが、強制される文字列は、一部の文字を表現できないエンコーディングにトランスコードする必要があります。このケースについては、以前の回答で説明しまし
eggyal 2014年

5
すばらしい答えです。これは、開発者が実際に知っておくべきことを詳しく説明しているので、さらに上になるはずです。それを修正する方法だけでなく、物事が彼らのやり方で起こっている理由を本当に理解しています。
マーク

ありがとう、今日は私に何かを教えてくれた。
briankip 2015年

66

将来のGoogle社員のためのディスカッションに2cを追加します。

varcharパラメータを受け取ったカスタム関数を使用すると、次のエラーが発生する同様の問題を調査していました。

Illegal mix of collations (utf8_unicode_ci,IMPLICIT) and 
(utf8_general_ci,IMPLICIT) for operation '='

次のクエリを使用します。

mysql> show variables like "collation_database";
    +--------------------+-----------------+
    | Variable_name      | Value           |
    +--------------------+-----------------+
    | collation_database | utf8_general_ci |
    +--------------------+-----------------+

テーブルがutf8_unicode_ciを使用して定義されているのに対して、DBはutf8_general_ciを使用していることがわかりました

mysql> show table status;
    +--------------+-----------------+
    | Name         | Collation       |
    +--------------+-----------------+
    | my_view      | NULL            |
    | my_table     | utf8_unicode_ci |
    ...

ビューの照合順序がNULLであることに注意してください。このクエリは1つのビューに対してnullを示していますが、ビューと関数には照合順序の定義があるようです。使用される照合は、ビュー/関数の作成時に定義されたDB照合です。

悲しい解決策は、db照合順序を変更し、ビュー/関数を再作成して、現在の照合順序を使用するように強制することでした。

  • データベースの照合を変更する:

    ALTER DATABASE mydb DEFAULT COLLATE utf8_unicode_ci;
  • テーブル照合の変更:

    ALTER TABLE mydb CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

これが誰かの役に立つことを願っています。


12
照合順序は列レベルでも設定できます。あなたはでそれを表示することができますshow full columns from my_table;
ジョナサン・トラン

ありがとうございました。スキーマを削除し、正しいデフォルトの照合で再作成し、すべてを再インポートしました。
JRun、

1
@JonathanTranありがとうございます!すべてのテーブル、データベース、接続に文字セットと照合順序を設定しましたが、それでもエラーが発生していました。照合順序が列に設定されていません!私はそれを修正しましたalter table <TABLE> modify column <COL> varchar(255) collate utf8_general_ci;
クロエ

2
将来のGoogle社員向けの補足:データベース、テーブル、フィールドがすべて同じ照合順序であっても、接続で同じ照合順序が使用されていることを確認する必要もあります。すべてに»utf8mb4_unicode_ci«がありSHOW session variables like '%collation%';ますが、»collat​​ion_connection«は»utf8mb4_general_ci«であることがわかりますか?その後、SET collation_connection = utf8mb4_unicode_ci事前に実行します。
pixelbrackets 2017年

ありがとうございました!これを追跡するのにしばらくかかりました。テーブルは同じ照合である必要があるだけでなく、DBもそうでなければなりません!
モト

15

特に大量のデータを含むデータベースでは、文字セットを変換することが危険な場合があります。「バイナリ」演算子を使用するのが最善の方法だと思います。

e.g : WHERE binary table1.column1 = binary table2.column1

10

同様の問題があり、文字列変数で FIND_IN_SETプロシージャを使用しようとしました。

SET @my_var = 'string1,string2';
SELECT * from my_table WHERE FIND_IN_SET(column_name,@my_var);

エラーを受け取りました

エラーコード:1267。操作 'find_in_set'の照合(utf8_unicode_ci、IMPLICIT)と(utf8_general_ci、IMPLICIT)の不正な組み合わせ

短い答え:

任意のcollat​​ion_YYYYの変数を変更する必要はあり、ちょうど正しい照合を追加していない、あなたの変数宣言の隣に、すなわち

SET @my_var = 'string1,string2' COLLATE utf8_unicode_ci;
SELECT * from my_table WHERE FIND_IN_SET(column_name,@my_var);

長い答え:

まず、照合変数を確認しました。

mysql> SHOW VARIABLES LIKE 'collation%';
    +----------------------+-----------------+
    | Variable_name        | Value           |
    +----------------------+-----------------+
    | collation_connection | utf8_general_ci |
    +----------------------+-----------------+
    | collation_database   | utf8_general_ci |
    +----------------------+-----------------+
    | collation_server     | utf8_general_ci |
    +----------------------+-----------------+

次に、テーブルの照合順序を確認しました。

mysql> SHOW CREATE TABLE my_table;

CREATE TABLE `my_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `column_name` varchar(40) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=125 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

これは、テーブルがutf8_unicode_ciとして構成されているときに、変数がutf8_general_ciのデフォルトの照合で構成されたことを意味します。

変数宣言の横にCOLLATEコマンドを追加することにより、変数の照合順序は、テーブルに構成された照合順序と一致しました。



2

リテラルが含まれる場合の解決策。

Pentaho Data Integrationを使用していますが、SQL構文を指定できません。非常に単純なDBルックアップを使用すると、「操作 '='の照合(cp850_general_ci、COERCIBLE)と(latin1_swedish_ci、COERCIBLE)の照合の不正な組み合わせ」というエラーが発生しました。

生成されたコードは、「SELECT DATA_DATE AS latest_DATA_DATE FROM hr_cc_normalised_data_date_v WHERE PSEUDO_KEY =?」でした。

ストーリーを短くするために、ルックアップはビューに対するものであり、私が発行したとき

mysql> show full columns from hr_cc_normalised_data_date_v;
+------------+------------+-------------------+------+-----+
| Field      | Type       | Collation         | Null | Key |
+------------+------------+-------------------+------+-----+
| PSEUDO_KEY | varchar(1) | cp850_general_ci  | NO   |     |
| DATA_DATE  | varchar(8) | latin1_general_cs | YES  |     |
+------------+------------+-------------------+------+-----+

「cp850_general_ci」の由来を説明しています。

ビューは単に「SELECT 'X'、......」で作成されました。このような手動リテラルによると、このように「latin1」および「latin1_general_cs」として正しく定義されたサーバー設定から文字セットと照合順序を継承する必要があります明らかに起こらなかった私はビューの作成にそれを強制しました

CREATE OR REPLACE VIEW hr_cc_normalised_data_date_v AS
SELECT convert('X' using latin1) COLLATE latin1_general_cs        AS PSEUDO_KEY
    ,  DATA_DATE
FROM HR_COSTCENTRE_NORMALISED_mV
LIMIT 1;

これで、両方の列のlatin1_general_csが表示され、エラーはなくなりました。:)


1

MySQLは、それらを同じものに強制できない限り、混合照合を本当に嫌います(これは明らかにあなたの場合には実行不可能です)。同じ照合をCOLLATE句で強制的に使用することはできませんか?(またはBINARY該当する場合はより簡単なショートカット...)。


これはMySQLに固有のものですか?他のシステムは、明らかに同等の優先順位の互換性のない照合の組み合わせをどのように処理しますか?
eggyal 2014年

リンクが無効です。
Benubird 2014

1

問題のある列が「ハッシュ」である場合は、次のことを考慮してください...

「ハッシュ」がバイナリ文字列の場合、実際にはBINARY(...)データ型を使用する必要があります。

「ハッシュ」が16進数文字列である場合、utf8は必要ありません。文字チェックなどのため、これを避ける必要があります。たとえば、MySQL MD5(...)は固定長の32バイトの16進数文字列を生成します。 SHA1(...)40バイトの16進文字列を提供します。これはCHAR(32) CHARACTER SET ascii(またはsha1の場合は40)に格納できます。

または、さらに良いことに、に保存UNHEX(MD5(...))BINARY(16)ます。これにより、カラムのサイズが半分になります。(ただし、印刷することはSELECT HEX(hash) ...できません) 。

2つのBINARY列を比較しても、照合の問題はありません。


1

非常に興味深い...さあ、準備をしてください。私はすべての「コレート追加」ソリューションを調べましたが、それらはバンドエイドの修正です。実際のところ、データベースの設計は「悪い」ものでした。はい、標準の変更と新しいものが追加されます。何とか何とかしますが、それは悪いデータベース設計の事実を変えません。クエリを機能させるためだけに、SQLステートメント全体に「照合」を追加する方法を拒否します。私のために機能し、将来的にコードを微調整する必要を実質的に排除する唯一のソリューションは、私が一緒に暮らし、長期的に受け入れる文字セットと一致するようにデータベース/テーブルを再設計することです。この場合、文字セット " utf8mb4」。

したがって、この「不正な」エラーメッセージが発生した場合の解決策は、データベースとテーブルを再設計することです。それはそれが鳴るよりもはるかに簡単かつ迅速です。データをエクスポートしてCSVから再インポートする必要がない場合もあります。データベースの文字セットを変更し、テーブルのすべての文字セットが一致していることを確認してください。

次のコマンドを使用してガイドします。

SHOW VARIABLES LIKE "collation_database";
SHOW TABLE STATUS;

さて、あちこちに「collat​​e」を追加して、forces fulls「overrides」でコードを強化するのを楽しんでいるのであれば、私の推測になります。



0

照合に関する問題のもう1つの原因はmysql.procテーブルです。保存手順と機能の照合を確認します。

SELECT
  p.db, p.db_collation, p.type, COUNT(*) cnt
FROM mysql.proc p
GROUP BY p.db, p.db_collation, p.type;

列にも注意しmysql.proc.collation_connectionてくださいmysql.proc.character_set_client


0

phpMyAdminがインストールされている場合は、次のリンクにある指示に従ってください。https://mediatemple.net/community/products/dv/204403914/default-mysql-character-set-and-collat​​ion照合に一致する必要がありますデータベースのすべてのテーブル、およびテーブルのフィールドを使用して、すべてのストアドプロシージャと関数を再コンパイルします。これで、すべてが再び機能するはずです。


-1

を使用ALTER DATABASE mydb DEFAULT COLLATE utf8_unicode_ci;しましたが、機能しませんでした。

このクエリでは:

Select * from table1, table2 where table1.field = date_format(table2.field,'%H');

私にとってこの作品:

Select * from table1, table2 where concat(table1.field) = date_format(table2.field,'%H');

はいconcat


テーブルとその列の照合順序を確認します(テーブルのステータスを表示し、table1の列全体を表示します)。テーブルが間違った照合ですでに作成されている場合、alter databaseを使用しても機能しません。
Ariel T

ALTER DATABASE mydb DEFAULT COLLATE ...私のために働いたので賛成です。データベースを削除して再作成し、バックアップからロードできるので、私には利点があったかもしれません。
tobixen 2013

-2

このコードは、データベースのRun SQLクエリ内に配置する必要があります

SQLクエリウィンドウ

ALTER TABLE `table_name` CHANGE `column_name` `column_name`   VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL;

table_nameとcolumn_nameを適切な名前に置き換えてください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.