Mezcla ilegal de intercalaciones (utf8_unicode_ci, IMPLICIT) y (utf8_general_ci, IMPLICIT) para la operación '='

160

Mensaje de error en MySql:

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

He leído otras publicaciones y no he podido resolver este problema. La parte afectada es algo similar a esto:

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;

El procedimiento almacenado que estoy usando es este:

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

Estaba probando con php, pero el mismo error se da con SQLyog. También probé recrear todo el DB pero no sirvió de nada.

Cualquier ayuda será muy apreciada.

Manatax
fuente

Respuestas:

220

La clasificación predeterminada para los parámetros del procedimiento almacenado es utf8_general_ciy no puede mezclar clasificaciones, por lo que tiene cuatro opciones:

Opción 1 : agregue COLLATEa su variable de entrada:

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

Opción 2 : agregar COLLATEa la WHEREcláusula:

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

Opción 3 : agréguelo a la INdefinición del parámetro:

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

Opción 4 : alterar el campo en sí:

ALTER TABLE users CHARACTER SET utf8 COLLATE utf8_general_ci;

A menos que necesite ordenar los datos en orden Unicode, sugeriría alterar todas sus tablas para usar la utf8_general_ciintercalación, ya que no requiere cambios de código y acelerará un poco la clasificación.

ACTUALIZACIÓN : utf8mb4 / utf8mb4_unicode_ci es ahora el conjunto de caracteres preferido / método de clasificación. Se desaconseja utf8_general_ci, ya que la mejora del rendimiento es insignificante. Ver https://stackoverflow.com/a/766996/1432614

Ross Smith II
fuente
1
También es posible añadir COLLATE utf8_unicode_cia las constantes de cadena: SET @EMAIL = '[email protected]' COLLATE utf8_unicode_ci;. Es especialmente útil si está ejecutando un script desde una consola, donde la codificación predeterminada de la consola se aplica a la clasificación de las constantes de su cadena.
gaborsch
O suelte la base de datos y cree una nueva con utf8_general_ci; colación.
Oleksii Kyslytsyn 01 de
2
Para referencia futura, no cambie todas sus tablas a utf8_general_ci a menos que comprenda las diferencias entre las dos intercalaciones.
Manatax
1
@GaborSch Agregar la clasificación a las variables de cadena fue la solución para mí, escribí una respuesta detallada al respecto antes de notar su comentario.
nkatsar
Estoy obteniendo el mismo error, excepto en (utf8mb4_unicode_ci, IMPLICIT)lugar de (utf8_unicode_ci, IMPLICIT). estoy eliminando datos de la web usando python, luego creando un archivo CSV con los datos eliminados, que luego proceso con un archivo PHP en mi servidor que carga los datos en mi base de datos. Todas mis tablas / columnas de MySQL se clasifican como utf8mb4_unicode_ci. ¿podría surgir el problema porque codifico los datos como utf8en python / csv?
oldboy
27

Pasé medio día buscando respuestas a un error idéntico de "Mezcla ilegal de colaciones" con conflictos entre utf8_unicode_ci y utf8_general_ci.

Encontré que algunas columnas en mi base de datos no se cotejaron específicamente utf8_unicode_ci . Parece que mysql compaginó implícitamente estas columnas utf8_general_ci .

Específicamente, ejecutar una consulta 'SHOW CREATE TABLE table1' generó algo como lo siguiente:

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

Tenga en cuenta que la línea 'col1' varchar (4) CHARACTER SET utf8 NOT NULL no tiene una clasificación especificada. Luego ejecuté la siguiente consulta:

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

Esto resolvió mi error "Mezcla ilegal de colaciones". Espero que esto pueda ayudar a alguien más por ahí.

Nate Vaughan
fuente
77
Gracias. 'MOSTRAR CREAR TABLA' es la forma más fácil de comprender y solucionar la causa raíz del problema.
joro
2
También tenga en cuenta que la especificación COLLATEde toda la tabla (es decir ALTER TABLE table1 CHARSET utf8 COLLATE utf8_unicode_ci) no solucionará el problema , debe hacerse para cada columna (problemática).
Skippy le Grand Gourou
6

Tuve un problema similar, pero se me ocurrió dentro del procedimiento, cuando mi parámetro de consulta se configuró usando la variable eg SET @value='foo'.

Lo que estaba causando esto no coincidía collation_connectiony la clasificación de la base de datos. Cambió collation_connectionpara coincidir collation_databasey el problema desapareció. Creo que este es un enfoque más elegante que agregar COLLATE después de param / value.

En resumen: todas las colaciones deben coincidir. Uso SHOW VARIABLESy asegúrese collation_connectiony collation_databasefósforo (también comprobar el cotejo tabla usando SHOW TABLE STATUS [table_name]).

bpile
fuente
1
Me ocurrió el mismo problema, evité cambiar las variables collation_YYY configurando la colación directamente en la declaración de variables. SET @my_var = 'string1,string2' COLLATE utf8_unicode_ci;
nkatsar
5

Un poco similar a @bpile answer, mi caso fue una configuración de entrada my.cnf collation-server = utf8_general_ci. Después de darme cuenta de eso (y después de probar todo lo anterior), cambié forzosamente mi base de datos a utf8_general_ci en lugar de utf8_unicode_ci y eso fue todo:

ALTER DATABASE `db` CHARACTER SET utf8 COLLATE utf8_general_ci;
Sebas
fuente
1
Es extraño que las configuraciones se extiendan tanto. Todos los valores predeterminados de clasificación deben establecerse en el mismo lugar.
Manatax
0

En mi propio caso tengo el siguiente error

Mezcla ilegal de intercalaciones (utf8_general_ci, IMPLICIT) y (utf8_unicode_ci, IMPLICIT) para la operación '='

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

Después de semanas de búsqueda en Google, noté que los dos campos que estoy comparando consisten en un nombre de clasificación diferente. El primero, es decir, el nombre de usuario es utf8_general_ci, mientras que el segundo es utf8_unicode_ci, así que volví a la estructura de la segunda tabla y cambié el segundo campo (matric_no) a utf8_general_ci y funcionó de maravilla.

Teejaygenius
fuente
0

A pesar de encontrar una enorme cantidad de preguntas sobre el mismo problema ( 1 , 2 , 3 , 4 ), nunca encontré una respuesta que tuviera en cuenta el rendimiento, incluso aquí.

Aunque ya se han dado múltiples soluciones de trabajo, me gustaría hacer una consideración de rendimiento.

EDITAR: Gracias a Manatax por señalar que la opción 1 no sufre problemas de rendimiento.

El uso de las opciones 1 y 2 , también conocido como el enfoque de fundición COLLATE , puede generar un posible cuello de botella, ya que no se utilizará ningún índice definido en la columna que cause un escaneo completo .

Aunque no probé la opción 3 , mi presentimiento es que sufrirá las mismas consecuencias que las opciones 1 y 2.

Por último, la opción 4 es la mejor opción para tablas muy grandes cuando es viable. Quiero decir que no hay otro uso que dependa de la recopilación original.

Considere esta consulta simplificada:

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

En mi ejemplo original, tuve muchas más uniones. Por supuesto, table1 y table2 tienen diferentes colaciones. El uso del operador de clasificación para emitir generará índices que no se utilizarán.

Vea la explicación de SQL en la imagen a continuación.

Explicación de la consulta visual cuando se usa la conversión COLLATE

Por otro lado, la opción 4 puede aprovechar las ventajas del índice posible y generar consultas rápidas.

En la imagen a continuación, puede ver la misma consulta que se ejecuta después de aplicar la Opción 4 , es decir, alterar la clasificación del esquema / tabla / columna.

Explicación de la consulta visual después de que se ha cambiado la clasificación y, por lo tanto, sin el reparto de clasificación

En conclusión, si el rendimiento es importante y puede alterar la clasificación de la tabla, vaya a la Opción 4 . Si tiene que actuar en una sola columna, puede usar algo como esto:

ALTER TABLE schema1.table1 MODIFY `field` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Raffaele
fuente
Gracias por su contribución, Raffaele, pero creo que la opción 1 usaría el índice, porque no está proyectando la tabla, sino el valor de comparación, incluso antes de pasarlo al SP.
Manatax
Gracias por señalar eso. Fue mi error. Edité mi respuesta en consecuencia.
Raffaele
0

Esto sucede cuando una columna se establece explícitamente en una clasificación diferente o la clasificación predeterminada es diferente en la tabla consultada.

si tiene muchas tablas en las que desea cambiar la clasificación al ejecutar esta consulta:

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;

esto generará las consultas necesarias para convertir todas las tablas para usar la clasificación correcta por columna

raam86
fuente
También ocurre cuando (como en mi caso) su intercalación predeterminada para SP es diferente de la intercalación utilizada para la tabla consultada.
Manatax