演算 '='の照合(utf8_unicode_ci、IMPLICIT)と(utf8_general_ci、IMPLICIT)の不正な組み合わせ


160

MySqlのエラーメッセージ:

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

私は他のいくつかの投稿を経験しましたが、この問題を解決することができませんでした。影響を受ける部分は次のようなものです。

CREATE TABLE users (
    userID INT UNSIGNED NOT NULL AUTO_INCREMENT,
    firstName VARCHAR(24) NOT NULL,
    lastName VARCHAR(24) NOT NULL,
    username VARCHAR(24) NOT NULL,
    password VARCHAR(40) NOT NULL,
    PRIMARY KEY (userid)
) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_unicode_ci;

CREATE TABLE products (
    productID INT UNSIGNED NOT NULL AUTO_INCREMENT,
    title VARCHAR(104) NOT NULL,
    picturePath VARCHAR(104) NULL,
    pictureThumb VARCHAR(104) NULL,
    creationDate DATE NOT NULL,
    closeDate DATE NULL,
    deleteDate DATE NULL,
    varPath VARCHAR(104) NULL,
    isPublic TINYINT(1) UNSIGNED NOT NULL DEFAULT '1',
    PRIMARY KEY (productID)
) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_unicode_ci;

CREATE TABLE productUsers (
    productID INT UNSIGNED NOT NULL,
    userID INT UNSIGNED NOT NULL,
    permission VARCHAR(16) NOT NULL,
    PRIMARY KEY (productID,userID),
    FOREIGN KEY (productID) REFERENCES products (productID) ON DELETE RESTRICT ON UPDATE NO ACTION,
    FOREIGN KEY (userID) REFERENCES users (userID) ON DELETE RESTRICT ON UPDATE NO ACTION
) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_unicode_ci;

私が使用しているストアドプロシージャは次のとおりです。

CREATE PROCEDURE updateProductUsers (IN rUsername VARCHAR(24),IN rProductID INT UNSIGNED,IN rPerm VARCHAR(16))
BEGIN
    UPDATE productUsers
        INNER JOIN users
        ON productUsers.userID = users.userID
        SET productUsers.permission = rPerm
        WHERE users.username = rUsername
        AND productUsers.productID = rProductID;
END

私はphpでテストしていましたが、SQLyogでも同じエラーが発生します。また、DB全体を再作成することもテストしましたが、うまくいきません。

どんな助けでも大歓迎です。

回答:


220

ストアドプロシージャパラメーターの既定の照合順序はでutf8_general_ciあり、照合順序を混在させることはできないため、4つのオプションがあります。

オプション1COLLATE入力変数に追加します。

SET @rUsername = aname COLLATE utf8_unicode_ci; -- COLLATE added
CALL updateProductUsers(@rUsername, @rProductID, @rPerm);

オプション2:追加COLLATEWHERE句:

CREATE PROCEDURE updateProductUsers(
    IN rUsername VARCHAR(24),
    IN rProductID INT UNSIGNED,
    IN rPerm VARCHAR(16))
BEGIN
    UPDATE productUsers
        INNER JOIN users
        ON productUsers.userID = users.userID
        SET productUsers.permission = rPerm
        WHERE users.username = rUsername COLLATE utf8_unicode_ci -- COLLATE added
        AND productUsers.productID = rProductID;
END

オプション3INパラメータ定義に追加します。

CREATE PROCEDURE updateProductUsers(
    IN rUsername VARCHAR(24) COLLATE utf8_unicode_ci, -- COLLATE added
    IN rProductID INT UNSIGNED,
    IN rPerm VARCHAR(16))
BEGIN
    UPDATE productUsers
        INNER JOIN users
        ON productUsers.userID = users.userID
        SET productUsers.permission = rPerm
        WHERE users.username = rUsername
        AND productUsers.productID = rProductID;
END

オプション4:フィールド自体を変更します。

ALTER TABLE users CHARACTER SET utf8 COLLATE utf8_general_ci;

Unicode順でデータを並べ替える必要がない限り、utf8_general_ci照合を使用するようにすべてのテーブルを変更することをお勧めします。コードを変更する必要がなく、並べ替えがわずかに高速化されるためです。

UPDATE:utf8mb4 / utf8mb4_unicode_ciが、推奨される文字セット/照合方法になりました。パフォーマンスの向上はごくわずかなので、utf8_general_ciは推奨されません。https://stackoverflow.com/a/766996/1432614を参照してください


1
COLLATE utf8_unicode_ci文字列定数に追加することもできます:SET @EMAIL = 'abc@def.com' COLLATE utf8_unicode_ci;。これは、コンソールからスクリプトを実行している場合に特に役立ちます。コンソールのデフォルトのエンコーディングは、文字列定数の照合に適用されます。
gaborsch 2016

または、データベースを削除し、utf8_general_ciを使用して新規に作成します。照合。
Oleksii Kyslytsyn 2017

2
将来の参照のために、2つの照合順序の違いを理解していない限り、すべてのテーブルをutf8_general_ciに変更しないでください。
Manatax 2017

1
@GaborSch文字列変数にコレートを追加することが私にとっての解決策でした。コメントに気付く前に、それについて詳細な回答を書きました。
nkatsar

(utf8mb4_unicode_ci, IMPLICIT)代わりを除いて、同じエラーが発生します(utf8_unicode_ci, IMPLICIT)。私はPythonを使用してWebからデータをスクレイピングし、スクレイピングしたデータを含むCSVファイルを作成します。次に、サーバーにあるPHPファイルを使用してデータをデータベースにアップロードします。MySQLのすべてのテーブル/列はとして照合されutf8mb4_unicode_ciます。utf8python / csvのようにデータをエンコードしているため、問題が発生している可能性がありますか?
oldboy

27

utf8_unicode_ciとutf8_general_ciの競合を伴う同一の「Illegal mix of collat​​ions」エラーに対する回答を検索するのに半日かかりました。

データベース内の一部の列が明確に照合されていないutf8_unicode_ciであることがわかりました。mysqlはこれらの列utf8_general_ciを暗黙的に照合したようです

具体的には、「SHOW CREATE TABLE table1」クエリを実行すると、次のようなものが出力されます。

| table1 | CREATE TABLE `table1` (
`id` int(11) NOT NULL,
`col1` varchar(4) CHARACTER SET utf8 NOT NULL,
`col2` int(11) NOT NULL,
PRIMARY KEY (`col1`,`col2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |

'col1' varchar(4)CHARACTER SET utf8 NOT NULLには照合順序が指定されていないことに注意してください。次に、次のクエリを実行しました。

ALTER TABLE table1 CHANGE col1 col1 VARCHAR(4) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL;

これにより、「不正な照合順序の混在」エラーが解決されました。これが他の誰かを助けることを願っています。


7
ありがとう。「SHOW CREATE TABLE」は、問題の根本的な原因を理解して修正する最も簡単な方法です。
joro 2016年

2
またCOLLATE、テーブル全体(つまりALTER TABLE table1 CHARSET utf8 COLLATE utf8_unicode_ci)を指定しても問題は解決されないことに注意してください。これは、(問題のある)列ごとに行う必要があります。
Skippy le Grand Gourou

6

同様の問題がありましたが、クエリパラメータが変数egを使用して設定されたときに、プロシージャ内で発生しましたSET @value='foo'

これを引き起こしていたのは、不一致collation_connectionとデータベース照合でした。collation_connection一致するように変更されcollation_database、問題は解消しました。これはparam / valueの後にCOLLATEを追加するよりもエレガントなアプローチだと思います。

要約すると、すべての照合順序が一致する必要があります。を使用SHOW VARIABLESして確認しcollation_connectioncollation_database一致させます(また、を使用してテーブルの照合を確認しますSHOW TABLE STATUS [table_name])。


1
同じ問題が私にも起こりました。変数宣言で直接照合順序を設定することにより、collat​​ion_YYY変数を変更しないようにしました。 SET @my_var = 'string1,string2' COLLATE utf8_unicode_ci;
nkatsar

5

@bpile回答に少し似ていますが、私のケースはmy.cnfエントリ設定collation-server = utf8_general_ciでした。それを理解した後(そして上記のすべてを試した後)、データベースをutf8_unicode_ciではなくutf8_general_ciに強制的に切り替えました。

ALTER DATABASE `db` CHARACTER SET utf8 COLLATE utf8_general_ci;

1
設定があまりにも広がっているのは奇妙です。照合のデフォルトはすべて同じ場所に設定する必要があります。
Manatax 16

0

私自身の場合、私は次のエラーがあります

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

$ this-> db-> select( "users.username as matric_no、CONCAT(users.surname、 ''、users.first_name、 ''、users.last_name)as fullname")-> join( 'users'、 'users .username = classroom_students.matric_no '、' left ')-> where(' classroom_students.session_id '、$ session)-> where(' classroom_students.level_id '、$ level)-> where(' classroom_students.dept_id '、$ dept );

何週間かのグーグル検索の後、比較している2つのフィールドが異なる照合名で構成されていることに気付きました。最初の1つ、つまりユーザー名はutf8_general_ciで、2番目はutf8_unicode_ciなので、2番目のテーブルの構造に戻り、2番目のフィールド(matric_no)をutf8_general_ciに変更しました。


0

同じ問題(疑問の膨大な数を見つけるのにもかかわらず1234)私もここでは、考慮した性能を取った答えを見つけたことがありません。

すでに複数の実用的なソリューションが提供されていますが、パフォーマンスを考慮したいと思います。

編集:オプション1はパフォーマンスの問題に悩まされないことを指摘してくれたManataxに感謝します。

使用するオプション1と 2を、別名COLLATEの列に定義された任意のインデックスが原因で使用されることはありません原因キャストアプローチは、潜在的なボトルネックにつながることができますフルスキャンを

オプション3を試したわけではありませんが、オプション1と 2 同じ結果になると思います。

最後に、オプション4は、実行可能な非常に大きなテーブルに最適なオプションです。つまり、元の照合に依存する他の使用法はありません。

この単純化されたクエリを考えてみましょう:

SELECT 
    *
FROM
    schema1.table1 AS T1
        LEFT JOIN
    schema2.table2 AS T2 ON T2.CUI = T1.CUI
WHERE
    T1.cui IN ('C0271662' , 'C2919021')
;

元の例では、さらに多くの結合がありました。もちろん、table1とtable2の照合順序は異なります。照合演算子を使用してキャストすると、インデックスが使用されなくなります。

以下の図のSQLの説明を参照してください。

COLLATEキャストを使用する場合のビジュアルクエリの説明

一方、オプション4は、可能なインデックスを活用して、クエリを高速化できます。

以下の図では、オプション4を適用した後に同じクエリが実行されていることがわかります。つまり、スキーマ/テーブル/列の照合順序が変更されています。

照合順序が変更された後、したがって照合順序キャストがない場合のビジュアルクエリの説明

結論として、パフォーマンスが重要であり、テーブルの照合を変更できる場合は、オプション4に進みます。単一の列を操作する必要がある場合は、次のようなものを使用できます。

ALTER TABLE schema1.table1 MODIFY `field` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Raffaeleの貢献に感謝しますが、オプション1ではインデックスを使用すると思います。テーブルをキャストするのではなく、SPに渡す前に比較値を使用するためです。
Manatax

ご指摘いただきありがとうございます。それは私の間違いでした。私はそれに応じて私の答えを編集しました。
Raffaele

0

これは、列が明示的に別の照合に設定されている場合、またはクエリされたテーブルで既定の照合が異なる場合に発生します。

多くのテーブルがあり、照合を変更したい場合は、次のクエリを実行します。

select concat('ALTER TABLE ', t.table_name , ' CONVERT TO CHARACTER 
SET utf8 COLLATE utf8_unicode_ci;') from (SELECT table_name FROM 
information_schema.tables where table_schema='SCHRMA') t;

これにより、すべてのテーブルを変換して列ごとに正しい照合を使用するために必要なクエリが出力されます


(私の場合のように)SPのデフォルトの照合順序が、照会されたテーブルに使用されている照合順序と異なる場合にも発生します。
Manatax 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.