Unzulässige Mischung von Kollatierungen (utf8_unicode_ci, IMPLICIT) und (utf8_general_ci, IMPLICIT) für die Operation '='

160

Fehlermeldung auf MySql:

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

Ich habe mehrere andere Beiträge durchgesehen und konnte dieses Problem nicht lösen. Der betroffene Teil ist ungefähr so:

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;

Die gespeicherte Prozedur, die ich verwende, ist folgende:

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

Ich habe mit PHP getestet, aber der gleiche Fehler wird mit SQLyog angezeigt. Ich habe auch getestet, die gesamte DB neu zu erstellen, aber nicht gut.

Jede Hilfe wird sehr geschätzt.

Manatax
quelle

Antworten:

220

Die Standardkollatierung für gespeicherte Prozedurparameter lautet utf8_general_ciund Sie können Kollatierungen nicht mischen, sodass Sie vier Optionen haben:

Option 1 : Hinzufügen COLLATEzu Ihrer Eingabevariablen:

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

Option 2 : COLLATEZur WHEREKlausel hinzufügen :

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

Option 3 : Fügen Sie es der INParameterdefinition hinzu:

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

Option 4 : Ändern Sie das Feld selbst:

ALTER TABLE users CHARACTER SET utf8 COLLATE utf8_general_ci;

Sofern Sie keine Daten in Unicode-Reihenfolge sortieren müssen, würde ich empfehlen, alle Ihre Tabellen so zu ändern, dass die utf8_general_ciSortierung verwendet wird, da keine Codeänderungen erforderlich sind und die Sortierung geringfügig beschleunigt wird.

UPDATE : utf8mb4 / utf8mb4_unicode_ci ist jetzt die bevorzugte Zeichensatz- / Sortiermethode. Von utf8_general_ci wird abgeraten, da die Leistungsverbesserung vernachlässigbar ist. Siehe https://stackoverflow.com/a/766996/1432614

Ross Smith II
quelle
1
Es ist auch möglich COLLATE utf8_unicode_ci, Zeichenfolgenkonstanten hinzuzufügen : SET @EMAIL = '[email protected]' COLLATE utf8_unicode_ci;. Dies ist besonders nützlich, wenn Sie ein Skript von einer Konsole aus ausführen, wobei die Standardcodierung der Konsole für die Sortierung Ihrer Zeichenfolgenkonstanten gilt.
Gaborsch
Oder löschen Sie die Datenbank und erstellen Sie eine neue mit utf8_general_ci. Kollation.
Oleksii Kyslytsyn
2
Ändern Sie zum späteren Nachschlagen nicht alle Ihre Tabellen in utf8_general_ci, es sei denn, Sie verstehen die Unterschiede zwischen den beiden Kollatierungen.
Manatax
1
@GaborSch Das Hinzufügen von Sortieren zu Zeichenfolgenvariablen war die Lösung für mich. Ich habe eine ausführliche Antwort darauf geschrieben, bevor ich Ihren Kommentar bemerkte.
Nkatsar
Ich bekomme den gleichen Fehler, außer (utf8mb4_unicode_ci, IMPLICIT)anstelle von (utf8_unicode_ci, IMPLICIT). Ich kratzte Daten aus dem Web mit Python und erstellte dann eine CSV-Datei mit den kratzenden Daten, die ich dann mit einer PHP-Datei auf meinem Server verarbeite, die die Daten in meine Datenbank hochlädt. Alle meine MySQL-Tabellen / Spalten werden als sortiert utf8mb4_unicode_ci. Könnte das Problem auftreten, weil ich die Daten wie utf8in Python / CSV codiere?
Oldboy
27

Ich habe einen halben Tag damit verbracht, nach Antworten auf einen identischen Fehler "Illegale Mischung von Kollatierungen" mit Konflikten zwischen utf8_unicode_ci und utf8_general_ci zu suchen.

Ich habe festgestellt, dass einige Spalten in meiner Datenbank nicht speziell nach utf8_unicode_ci sortiert wurden . Es scheint, dass MySQL diese Spalten utf8_general_ci implizit zusammengestellt hat .

Insbesondere beim Ausführen einer Abfrage 'SHOW CREATE TABLE table1' wurde Folgendes ausgegeben:

| 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 |

Beachten Sie, dass in der Zeile 'col1' varchar (4) CHARACTER SET utf8 NOT NULL keine Sortierung angegeben ist. Ich habe dann die folgende Abfrage ausgeführt:

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

Dies löste meinen Fehler "Illegale Mischung von Kollatierungen". Hoffe, das könnte jemand anderem da draußen helfen.

Nate Vaughan
quelle
7
Vielen Dank. 'SHOW CREATE TABLE' ist der einfachste Weg, um die Grundursache des Problems zu verstehen und zu beheben.
Joro
2
Beachten Sie auch, dass die Angabe COLLATEfür die gesamte Tabelle (dh ALTER TABLE table1 CHARSET utf8 COLLATE utf8_unicode_ci) das Problem nicht behebt , sondern für jede (problematische) Spalte erfolgen muss.
Skippy le Grand Gourou
6

Ich hatte ein ähnliches Problem, aber es fiel mir innerhalb der Prozedur ein, als mein Abfrageparameter unter Verwendung der Variablen z SET @value='foo'.

Was dies verursachte, war eine Nichtübereinstimmung collation_connectionund eine Datenbanksortierung. Geändert, um collation_connectionzu passen collation_databaseund Problem ging weg. Ich denke, dies ist eleganter als das Hinzufügen von COLLATE nach param / value.

Zusammenfassend: Alle Kollatierungen müssen übereinstimmen. Verwenden SHOW VARIABLESund sicherstellen collation_connectionund collation_databaseübereinstimmen (überprüfen Sie auch die Tabellensortierung mit SHOW TABLE STATUS [table_name]).

bpile
quelle
1
Das gleiche Problem ist mir passiert. Ich habe es vermieden, die Variablen collation_YYY zu ändern, indem ich die Kollatierung direkt in der Variablendeklaration festgelegt habe. SET @my_var = 'string1,string2' COLLATE utf8_unicode_ci;
Nkatsar
5

Ein bisschen ähnlich wie bei @bpile answer war mein Fall eine my.cnf-Eintragseinstellung collation-server = utf8_general_ci. Nachdem ich das erkannt hatte (und nachdem ich alles oben versucht hatte), habe ich meine Datenbank zwangsweise auf utf8_general_ci anstatt auf utf8_unicode_ci umgestellt und das wars:

ALTER DATABASE `db` CHARACTER SET utf8 COLLATE utf8_general_ci;
Sebas
quelle
1
Es ist seltsam, dass die Konfigurationen so weit verteilt sind. Alle Sortierstandards sollten an derselben Stelle festgelegt werden.
Manatax
0

In meinem Fall habe ich folgenden Fehler

Unzulässige Mischung von Kollatierungen (utf8_general_ci, IMPLICIT) und (utf8_unicode_ci, IMPLICIT) für die Operation '='

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

Nach wochenlanger Google-Suche habe ich festgestellt, dass die beiden Felder, die ich vergleiche, aus unterschiedlichen Sortierungsnamen bestehen. Der erste, dh der Benutzername, ist utf8_general_ci, während der zweite utf8_unicode_ci ist. Ich bin also zur Struktur der zweiten Tabelle zurückgekehrt und habe das zweite Feld (matric_no) in utf8_general_ci geändert, und es hat wie ein Zauber funktioniert.

Teejaygenius
quelle
0

Obwohl ich eine enorme Anzahl von Fragen zu demselben Problem gefunden habe ( 1 , 2 , 3 , 4 ), habe ich auch hier nie eine Antwort gefunden, die die Leistung berücksichtigt.

Obwohl bereits mehrere Arbeitslösungen angegeben wurden, möchte ich eine Leistungsüberlegung anstellen.

EDIT: Vielen Dank an Manatax für den Hinweis, dass Option 1 keine Leistungsprobleme aufweist.

Die Verwendung von Option 1 und 2 , auch bekannt als COLLATE- Cast-Ansatz, kann zu einem möglichen Engpass führen, da kein in der Spalte definierter Index verwendet wird, was zu einem vollständigen Scan führt .

Obwohl ich Option 3 nicht ausprobiert habe, ist meine Vermutung, dass es die gleichen Konsequenzen wie Option 1 und 2 haben wird.

Schließlich ist Option 4 die beste Option für sehr große Tabellen, wenn dies möglich ist. Ich meine, es gibt keine andere Verwendung, die auf der ursprünglichen Zusammenstellung beruht.

Betrachten Sie diese vereinfachte Abfrage:

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

In meinem ursprünglichen Beispiel hatte ich viel mehr Verknüpfungen. Natürlich haben Tabelle1 und Tabelle2 unterschiedliche Sortierungen. Wenn Sie den Sortieroperator zum Umwandeln verwenden, werden keine Indizes verwendet.

Siehe SQL-Erklärung im Bild unten.

Erläuterung der visuellen Abfrage bei Verwendung der COLLATE-Umwandlung

Andererseits kann Option 4 die Vorteile eines möglichen Index nutzen und zu schnellen Abfragen führen.

In der Abbildung unten sehen Sie dieselbe Abfrage, die nach Anwendung von Option 4 ausgeführt wird , auch bekannt als Ändern der Schema- / Tabellen- / Spaltenkollatierung.

Visuelle Abfrage Erläuterung, nachdem die Sortierung geändert wurde und daher ohne die Sortierbesetzung

Wenn die Leistung wichtig ist und Sie die Sortierung der Tabelle ändern können, wählen Sie abschließend Option 4 . Wenn Sie auf eine einzelne Spalte reagieren müssen, können Sie Folgendes verwenden:

ALTER TABLE schema1.table1 MODIFY `field` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Raffaele
quelle
Vielen Dank für Ihren Beitrag Raffaele, aber ich glaube, die Option 1 würde den Index verwenden, da Sie nicht die Tabelle, sondern den Vergleichswert gießen, bevor Sie ihn überhaupt an den SP übergeben.
Manatax
Vielen Dank für den Hinweis. Es war mein Fehler. Ich habe meine Antwort entsprechend bearbeitet.
Raffaele
0

Dies geschieht, wenn eine Spalte explizit auf eine andere Sortierung festgelegt ist oder die Standardkollatierung in der abgefragten Tabelle unterschiedlich ist.

Wenn Sie viele Tabellen haben, möchten Sie die Sortierung beim Ausführen dieser Abfrage ändern:

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;

Dadurch werden die Abfragen ausgegeben, die zum Konvertieren aller Tabellen erforderlich sind, um die richtige Sortierung pro Spalte zu verwenden

raam86
quelle
Dies tritt auch auf, wenn (wie in meinem Fall) Ihre Standardkollatierung für SP von der für die abgefragte Tabelle verwendeten Kollatierung abweicht.
Manatax