MySQLのストアドプロシージャを使用して選択しようとすると、以下のエラーが発生します。
オペレーション '='の照合(latin1_general_cs、IMPLICIT)と(latin1_general_ci、IMPLICIT)の不正な組み合わせ
ここで何がうまくいかないのかについて何か考えはありますか?
テーブルの照合順序はlatin1_general_ci
であり、where句の列の照合順序はlatin1_general_cs
です。
MySQLのストアドプロシージャを使用して選択しようとすると、以下のエラーが発生します。
オペレーション '='の照合(latin1_general_cs、IMPLICIT)と(latin1_general_ci、IMPLICIT)の不正な組み合わせ
ここで何がうまくいかないのかについて何か考えはありますか?
テーブルの照合順序はlatin1_general_ci
であり、where句の列の照合順序はlatin1_general_cs
です。
回答:
これは通常、互換性のない照合の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;
文字列の1つ(または両方)の照合を変更して一致するようにするかCOLLATE
、式に句を追加します。
とにかく、この「照合」のものは何ですか?
一般に文字セットと照合順序で説明されているように:
文字セットは、シンボルとエンコーディングのセットです。照合は、文字セット内の文字を比較するためのルールのセットです。架空の文字セットの例を使用して、区別を明確にしましょう。
「
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
」というルールなど)。
さらなる例は、照合の影響の例に示されています。
さて、しかし、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
照合と_ci
or_cs
照合が混在する演算の場合、_bin
照合が使用されます。これは、非バイナリ文字列とバイナリ文字列を混在させる操作が、オペランドをバイナリ文字列として評価する方法と似ていますが、データ型ではなく照合順序である点が異なります。
では、「照合の違法な組み合わせ」とは何でしょうか。
「照合の違法な組み合わせ」は、式が異なる照合の2つの文字列を比較するが、保磁力は等しい場合に発生し、保磁力のルールは競合の解決に役立ちません。これは、上記の引用の3番目の箇条書きで説明されている状況です。
質問で与えられた特定のエラーIllegal mix of collations (latin1_general_cs,IMPLICIT) and (latin1_general_ci,IMPLICIT) for operation '='
は、等しい保磁力の2つの非Unicode文字列の間に等しい比較があったことを示しています。さらに、照合順序はステートメントで明示的に指定されたのではなく、文字列のソース(列のメタデータなど)から暗示されていたことがわかります。
それはすべて非常にうまくいきますが、そのようなエラーをどのように解決しますか?
上記で引用したマニュアルの抜粋が示唆するように、この問題はいくつかの方法で解決できます。そのうちの2つは賢明であり、推奨されます。
ストリングの1つ(または両方)の照合を変更して、ストリングが一致し、あいまいさがなくなるようにします。
これを行う方法は、文字列がどこから来たかによって異なります。リテラル式は、collation_connection
システム変数で指定された照合を受け取ります。テーブルの値は、列のメタデータで指定された照合順序を取ります。
1つの文字列を強制できないようにします。
上記から次の引用を省略しました:
MySQLは、次のように強制可能性の値を割り当てます。
したがってCOLLATE
、比較で使用される文字列の1つに句を追加するだけで、その照合が強制的に使用されます。
他の人がこのエラーを解決するためだけに配備された場合、ひどく悪い習慣になりますが、
文字列の一方(または両方)に強制的に他の強制力の値を設定して、一方が優先されるようにします。
CONCAT()
またはCONCAT_WS()
を使用すると、強制力1の文字列になります。(ストアドルーチン内にある場合)パラメータ/ローカル変数を使用すると、強制力が2の文字列になります。
文字列の一方(または両方)のエンコーディングを変更して、一方がUnicodeになり、もう一方がUnicodeにならないようにします。
これは、を使用したトランスコーディングによって行うことができます。または、データの基礎となる文字セットを変更する(たとえば、列の変更、リテラル値の変更、またはクライアントからの異なるエンコーディングでの送信、および文字セットイントロデューサの変更/追加)。新しい文字セットで目的の文字をエンコードできない場合、エンコードを変更すると他の問題が発生することに注意してください。CONVERT(expr USING transcoding_name)
character_set_connection
character_set_client
文字列の一方(または両方)のエンコーディングを変更して両方が同じになるようにし、1つの文字列を変更して関連する_bin
照合を使用するようにします。
エンコーディングと照合順序を変更する方法については、上記で詳しく説明しています。照合によって提供されるよりも高度な照合ルールを実際に適用する必要がある場合、このアプローチはほとんど役に立ちません_bin
。
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;
これが誰かの役に立つことを願っています。
show full columns from my_table;
alter table <TABLE> modify column <COL> varchar(255) collate utf8_general_ci;
SHOW session variables like '%collation%';
ますが、»collation_connection«は»utf8mb4_general_ci«であることがわかりますか?その後、SET collation_connection = utf8mb4_unicode_ci
事前に実行します。
特に大量のデータを含むデータベースでは、文字セットを変換することが危険な場合があります。「バイナリ」演算子を使用するのが最善の方法だと思います。
e.g : WHERE binary table1.column1 = binary table2.column1
同様の問題があり、文字列変数で 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)の不正な組み合わせ
短い答え:
任意のcollation_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コマンドを追加することにより、変数の照合順序は、テーブルに構成された照合順序と一致しました。
すべてのデータベースとテーブルをutf8に変換するこのスクリプトを試すことができます。
リテラルが含まれる場合の解決策。
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が表示され、エラーはなくなりました。:)
MySQLは、それらを同じものに強制できない限り、混合照合を本当に嫌います(これは明らかにあなたの場合には実行不可能です)。同じ照合をCOLLATE句で強制的に使用することはできませんか?(またはBINARY
該当する場合はより簡単なショートカット...)。
問題のある列が「ハッシュ」である場合は、次のことを考慮してください...
「ハッシュ」がバイナリ文字列の場合、実際には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
列を比較しても、照合の問題はありません。
非常に興味深い...さあ、準備をしてください。私はすべての「コレート追加」ソリューションを調べましたが、それらはバンドエイドの修正です。実際のところ、データベースの設計は「悪い」ものでした。はい、標準の変更と新しいものが追加されます。何とか何とかしますが、それは悪いデータベース設計の事実を変えません。クエリを機能させるためだけに、SQLステートメント全体に「照合」を追加する方法を拒否します。私のために機能し、将来的にコードを微調整する必要を実質的に排除する唯一のソリューションは、私が一緒に暮らし、長期的に受け入れる文字セットと一致するようにデータベース/テーブルを再設計することです。この場合、文字セット " utf8mb4」。
したがって、この「不正な」エラーメッセージが発生した場合の解決策は、データベースとテーブルを再設計することです。それはそれが鳴るよりもはるかに簡単かつ迅速です。データをエクスポートしてCSVから再インポートする必要がない場合もあります。データベースの文字セットを変更し、テーブルのすべての文字セットが一致していることを確認してください。
次のコマンドを使用してガイドします。
SHOW VARIABLES LIKE "collation_database";
SHOW TABLE STATUS;
さて、あちこちに「collate」を追加して、forces fulls「overrides」でコードを強化するのを楽しんでいるのであれば、私の推測になります。
可能な解決策は、データベース全体をUTF8に変換することです(この質問も参照)。
phpMyAdminがインストールされている場合は、次のリンクにある指示に従ってください。https://mediatemple.net/community/products/dv/204403914/default-mysql-character-set-and-collation照合に一致する必要がありますデータベースのすべてのテーブル、およびテーブルのフィールドを使用して、すべてのストアドプロシージャと関数を再コンパイルします。これで、すべてが再び機能するはずです。
を使用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
。
このコードは、データベースのRun 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を適切な名前に置き換えてください。