web-dev-qa-db-ja.com

操作 '='の照合順序(utf8_unicode_ci、IMPLICIT)と(utf8_general_ci、IMPLICIT)の組み合わせが不正です

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全体を再作成することをテストしましたが、ダメです。

任意の助けは大歓迎です。

131
Manatax

4つの選択肢があります。

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

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

オプション2COLLATE句にWHEREを追加します。

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

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

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;

ストアドプロシージャパラメータの既定の照合順序はutf8_general_ciであり、照合順序を混在させることはできません。

データをUnicode順にソートする必要がない限り、コードの変更が不要で、ソート速度が少し速くなるため、すべてのテーブルをutf8_general_ci照合順序を使用するように変更することをお勧めします。

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

183
Ross Smith II

Utf8_unicode_ciとutf8_general_ciが競合している場合の「不正な照合順序の混在」エラーに対する回答の検索に半日費やしました。

データベースの一部の列が特に照合されていないことがわかりましたtf8_unicode_ci。 mysqlは暗黙的にこれらのカラムを照合したようですtf8_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)文字セットutf8 NOT NULLには照合順序が指定されていません。それから私は次のクエリを実行しました:

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

これにより、「不正な照合順序の混在」エラーが解決されました。これが他の誰かに役立つかもしれないと思います。

21
Nate Vaughan

私は同様の問題を抱えていました、しかし、私の問い合わせパラメータが変数を使用して設定されたとき、それはプロシージャの中で私に起こりました。 SET @value='foo'

これの原因はcollation_connectionとデータベースの照合順序の不一致でした。 collation_connectioncollation_databaseと一致するように変更し、問題は解決しました。これは、param/valueの後にCOLLATEを追加するよりも、もっとエレガントなアプローチだと思います。

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

5
bpile

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

ALTER DATABASE `db` CHARACTER SET utf8 COLLATE utf8_general_ci;
4
Sebas

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

操作 '='の照合順序(utf8_general_ci、IMPLICIT)と(utf8_unicode_ci、IMPLICIT)の組み合わせが不正です

$ this-> db-> select( "users.username of matric_no、CONCAT(users.surname、 ''、users.first_name、 ''、users.last_name)をフルネーム") - > join( 'users'、 'users .username = classroom_students.matric_no '、' left ') - > where(' classroom_students.session_id '、$ session) - > where(' classroom_students.level_id '、$レベル) - > where(' classroom_students.dept_id '、$ dept ;

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

0
Teejaygenius

これは、列が明示的に別の照合順序に設定されている場合、または照会された表でデフォルトの照合順序が異なる場合に発生します。

たくさんのテーブルがある場合は、このクエリを実行するときに照合順序を変更します。

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;

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

0
raam86

同じ問題について膨大な数の質問を見つけたにもかかわらず( 12 、、 4 )ここでも、パフォーマンスを考慮に入れた答えは見つかりませんでした。

複数の実用的な解決策がすでに与えられていますが、私は性能を考慮したいと思います。

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

オプションを使用する 1と 2、別名COLLAT​​Eキャストアプローチは、潜在的なボトルネックにつながる可能性があり、列に定義されたインデックスは使用されません。フルスキャンを引き起こします

私は試してみませんでしたがオプション3、私の口実はそれがオプションの同じ結果に苦しむということです 1と 2。

最後に、Option 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;
0
Raffaele