Mix illegale di regole di confronto (utf8_unicode_ci, IMPLICIT) e (utf8_general_ci, IMPLICIT) per l'operazione '='


160

Messaggio di errore su MySql:

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

Ho esaminato diversi altri post e non sono stato in grado di risolvere questo problema. La parte interessata è qualcosa di simile a questo:

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;

La procedura memorizzata che sto usando è questa:

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

Stavo testando con php, ma lo stesso errore è dato con SQLyog. Ho anche provato a ricreare l'intero DB, ma per niente bene.

Qualsiasi aiuto sarà molto apprezzato.

Risposte:


220

Le regole di confronto predefinite per i parametri della procedura memorizzata sono utf8_general_cie non è possibile combinare le regole di confronto, quindi sono disponibili quattro opzioni:

Opzione 1 : aggiungi COLLATEalla tua variabile di input:

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

Opzione 2 : aggiungi COLLATEalla WHEREclausola:

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

Opzione 3 : aggiungilo alla INdefinizione del parametro:

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

Opzione 4 : modifica il campo stesso:

ALTER TABLE users CHARACTER SET utf8 COLLATE utf8_general_ci;

A meno che non sia necessario ordinare i dati in ordine Unicode, suggerirei di modificare tutte le tabelle per utilizzare le utf8_general_ciregole di confronto, poiché non richiede modifiche al codice e accelererà leggermente gli ordinamenti.

AGGIORNAMENTO : utf8mb4 / utf8mb4_unicode_ci è ora il set di caratteri preferito / metodo di confronto. sconsigliamo utf8_general_ci, poiché il miglioramento delle prestazioni è trascurabile. Vedi https://stackoverflow.com/a/766996/1432614


1
E 'anche possibile aggiungere COLLATE utf8_unicode_cia costanti stringa: SET @EMAIL = 'abc@def.com' COLLATE utf8_unicode_ci;. È particolarmente utile se si esegue uno script da una console, in cui la codifica predefinita della console si applica alle regole di confronto delle costanti di stringa.
Gaborsch,

Oppure rilascia il database e creane uno nuovo con utf8_general_ci; collazione.
Oleksii Kyslytsyn,

2
Per riferimento futuro, non modificare tutte le tabelle in utf8_general_ci a meno che non si capiscano le differenze tra le due regole di confronto.
Manatax,

1
@GaborSch L'aggiunta di fascicolazione alle variabili stringa è stata la soluzione per me, ho scritto una risposta dettagliata a riguardo prima di notare il tuo commento.
nkatsar,

sto ottenendo lo stesso errore, tranne (utf8mb4_unicode_ci, IMPLICIT)invece di (utf8_unicode_ci, IMPLICIT). sto raschiando i dati dal web usando Python, quindi creando un file CSV con i dati raschiati, che quindi elaboro con un file PHP sul mio server che carica i dati nel mio database. tutte le mie tabelle / colonne MySQL sono raccolte come utf8mb4_unicode_ci. potrebbe sorgere il problema perché codifico i dati come utf8in Python / CSV?
Oldboy

27

Ho trascorso mezza giornata alla ricerca di risposte a un identico errore "Illegal mix of collations" con conflitti tra utf8_unicode_ci e utf8_general_ci.

Ho scoperto che alcune colonne del mio database non sono state specificamente raccolte utf8_unicode_ci . Sembra che mysql abbia implicitamente raccolto queste colonne utf8_general_ci .

In particolare, l'esecuzione di una query 'SHOW CREATE TABLE table1' ha prodotto qualcosa di simile al seguente:

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

Notare che la riga 'col1' varchar (4) SET DI CARATTERI utf8 NOT NULL non ha un confronto specificato. Ho quindi eseguito la seguente query:

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

Questo ha risolto il mio errore "Illegal mix of collations". Spero che questo possa aiutare qualcun altro là fuori.


7
Grazie. "SHOW CREATE TABLE" è il modo più semplice per comprendere e correggere la causa principale del problema.
joro,

2
Si noti inoltre che la specifica COLLATEdell'intera tabella (ovvero ALTER TABLE table1 CHARSET utf8 COLLATE utf8_unicode_ci) non risolverà il problema , ma deve essere eseguita per ogni colonna (problematica).
Skippy le Grand Gourou,

6

Ho avuto un problema simile, ma mi è venuto in mente la procedura, quando il mio parametro di query è stato impostato usando la variabile es SET @value='foo'.

Ciò che stava causando ciò era incompatibile collation_connectione regole di confronto del database. Modificato collation_connectionper adattarsi collation_databasee il problema è andato via. Penso che questo sia un approccio più elegante rispetto all'aggiunta di COLLATE dopo il parametro / valore.

Per riassumere: tutte le regole di confronto devono corrispondere. Usa SHOW VARIABLESe assicurati collation_connectione collation_databaseabbina (controlla anche le regole di confronto delle tabelle usando SHOW TABLE STATUS [table_name]).


1
Lo stesso problema mi è successo, ho evitato di modificare le variabili collation_YYY impostando le regole di confronto direttamente nella dichiarazione delle variabili. SET @my_var = 'string1,string2' COLLATE utf8_unicode_ci;
nkatsar,

5

Un po 'simile alla risposta di @bpile, il mio caso era un'impostazione della voce my.cnf collation-server = utf8_general_ci. Dopo aver capito che (e dopo aver provato tutto sopra), ho forzatamente cambiato il mio database in utf8_general_ci invece di utf8_unicode_ci e basta:

ALTER DATABASE `db` CHARACTER SET utf8 COLLATE utf8_general_ci;

1
È strano che le configurazioni siano così diffuse. Tutte le impostazioni predefinite di confronto devono essere impostate nello stesso posto.
Manatax,

0

Nel mio caso ho il seguente errore

Mix illegale di regole di confronto (utf8_general_ci, IMPLICIT) e (utf8_unicode_ci, IMPLICIT) per l'operazione '='

$ this-> db-> select ("nome_utente come matric_no, CONCAT (nome utente, '', nome_utente, '', nome_utente_utente) come nome completo") -> join ("utenti", "utenti .username = classroom_students.matric_no ',' left ') -> where (' classroom_students.session_id ', $ session) -> where (' classroom_students.level_id ', $ level) -> where (' classroom_students.dept_id ', $ dept );

Dopo settimane di ricerche su google ho notato che i due campi che sto confrontando sono composti da un nome di confronto diverso. Il primo, cioè il nome utente, è utf8_general_ci mentre il secondo è utf8_unicode_ci, quindi sono tornato alla struttura della seconda tabella e ho cambiato il secondo campo (matric_no) in utf8_general_ci e ha funzionato come un incantesimo.


0

Nonostante abbia trovato un numero enorme di domande sullo stesso problema ( 1 , 2 , 3 , 4 ) non ho mai trovato una risposta che tenga conto delle prestazioni, anche qui.

Sebbene siano già state fornite più soluzioni di lavoro, vorrei prendere in considerazione le prestazioni.

EDIT: Grazie a Manatax per aver sottolineato che l'opzione 1 non soffre di problemi di prestazioni.

L'uso delle opzioni 1 e 2 , noto anche come approccio cast di COLLATE , può portare a potenziali colli di bottiglia, poiché qualsiasi indice definito nella colonna non verrà utilizzato causando una scansione completa .

Anche se non ho provato l' opzione 3 , il mio sospetto è che subirà le stesse conseguenze delle opzioni 1 e 2.

Infine, l' opzione 4 è l'opzione migliore per tabelle molto grandi quando è praticabile. Voglio dire, non ci sono altri usi che si basano sulla raccolta originale.

Considera questa query semplificata:

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

Nel mio esempio originale, ho avuto molti più join. Naturalmente, table1 e table2 hanno regole di confronto diverse. L'uso dell'operatore di fascicolazione per il cast comporta la mancata utilizzazione degli indici.

Vedi la spiegazione di sql nella figura sotto.

Visual Query Spiegazione quando si utilizza il cast COLLATE

D'altra parte, l' opzione 4 può sfruttare i vantaggi dell'indice possibile e portare a query rapide.

Nell'immagine seguente, puoi vedere la stessa query in esecuzione dopo aver applicato l' opzione 4 , ovvero alterare le regole di confronto schema / tabella / colonna.

Visual Query Spiegazione dopo che il confronto è stato modificato e quindi senza il cast del confronto

In conclusione, se le prestazioni sono importanti e puoi modificare le regole di confronto della tabella, scegli l' opzione 4 . Se devi agire su una singola colonna, puoi usare qualcosa del genere:

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

Grazie per il tuo contributo Raffaele, ma credo che l'opzione 1 utilizzerebbe l'indice, perché non stai lanciando la tabella, ma il valore di confronto prima ancora di passarlo all'SP.
Manatax,

Grazie per la segnalazione. È stato un mio errore. Ho modificato la mia risposta di conseguenza.
Raffaele,

0

Ciò accade quando una colonna è impostata esplicitamente su un confronto diverso o il confronto predefinito è diverso nella tabella interrogata.

se si hanno molte tabelle che si desidera modificare le regole di confronto durante l'esecuzione di questa query:

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;

questo genererà le query necessarie per convertire tutte le tabelle per utilizzare le regole di confronto corrette per colonna


Succede anche quando (come nel mio caso) le regole di confronto predefinite per SP sono diverse dalle regole di confronto utilizzate per la tabella interrogata.
Manatax,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.