J'obtiens l'erreur ci-dessous lorsque j'essaie de faire une sélection via une procédure stockée dans MySQL.
Mélange illégal de classements (latin1_general_cs, IMPLICIT) et (latin1_general_ci, IMPLICIT) pour l'opération '='
Une idée de ce qui pourrait mal se passer ici?
Le classement de la table est latin1_general_ci
celui de la colonne dans la clause where latin1_general_cs
.
Réponses:
Cela est généralement dû à la comparaison de deux chaînes de classement incompatible ou à la tentative de sélection de données de classement différent dans une colonne combinée.
La clause
COLLATE
vous permet de spécifier le classement utilisé dans la requête.Par exemple, la
WHERE
clause suivante donnera toujours l'erreur que vous avez publiée:Votre solution consiste à spécifier un classement partagé pour les deux colonnes de la requête. Voici un exemple qui utilise la
COLLATE
clause:Une autre option consiste à utiliser l'
BINARY
opérateur:Votre solution pourrait ressembler à ceci:
ou,
la source
COLLATE latin1_general_ci
qui provoque une autre erreur:COLLATION 'utf8_general_ci' is not valid for CHARACTER SET 'latin1''
- même si vous n'avez pas de colonne avec CHARACTER SET 'latin1'! La solution consiste à utiliser le plâtre BINARY. Voir aussi cette questionTL; DR
Modifiez le classement de l'une (ou des deux) des chaînes afin qu'elles correspondent, ou bien ajoutez une
COLLATE
clause à votre expression.Quel est ce truc de "collation" de toute façon?
Comme indiqué sous Jeux de caractères et classements en général :
D'autres exemples sont donnés sous Exemples d'effet de classement .
D'accord, mais comment MySQL décide-t-il du classement à utiliser pour une expression donnée?
Tel que documenté sous le classement d'expressions :
Qu'est-ce qu'un "mélange illégal de classements"?
Un "mélange illégal de classements" se produit lorsqu'une expression compare deux chaînes de classements différents mais de coercibilité égale et que les règles de coercibilité ne peuvent pas aider à résoudre le conflit. C'est la situation décrite sous le troisième point de la citation ci-dessus.
L'erreur particulière donnée dans la question,
Illegal mix of collations (latin1_general_cs,IMPLICIT) and (latin1_general_ci,IMPLICIT) for operation '='
nous indique qu'il y avait une comparaison d'égalité entre deux chaînes non Unicode de coercibilité égale. Il nous indique en outre que les classements n'ont pas été indiqués explicitement dans la déclaration, mais ont plutôt été implicites à partir des sources des chaînes (telles que les métadonnées de colonne).C'est très bien, mais comment résoudre de telles erreurs?
Comme le suggèrent les extraits manuels cités ci-dessus, ce problème peut être résolu de plusieurs manières, dont deux sont sensées et à recommander:
Modifiez le classement de l'une (ou des deux) des chaînes afin qu'elles correspondent et qu'il n'y ait plus d'ambiguïté.
La façon dont cela peut être fait dépend de l'origine de la chaîne: les expressions littérales prennent le classement spécifié dans la
collation_connection
variable système; les valeurs des tables prennent le classement spécifié dans leurs métadonnées de colonne.Force une chaîne à ne pas être coercitive.
J'ai omis la citation suivante de ce qui précède:
Ainsi, le simple fait d'ajouter une
COLLATE
clause à l'une des chaînes utilisées dans la comparaison forcera l'utilisation de ce classement.Alors que les autres seraient une très mauvaise pratique s'ils étaient déployés simplement pour résoudre cette erreur:
Forcer l'une (ou les deux) des chaînes à avoir une autre valeur de coercibilité pour que l'une ait priorité.
L'utilisation de
CONCAT()
ouCONCAT_WS()
entraînerait une chaîne avec une coercibilité de 1; et (si dans une routine stockée) l'utilisation de paramètres / variables locales entraînerait des chaînes avec une coercibilité de 2.Modifiez les encodages de l'une (ou des deux) des chaînes afin que l'une soit Unicode et l'autre non.
Cela pourrait être fait via le transcodage avec ; ou en changeant le jeu de caractères sous-jacent des données (par exemple en modifiant la colonne, en changeant pour les valeurs littérales, ou en les envoyant du client dans un codage différent et en changeant / ajoutant un introducteur de jeu de caractères). Notez que la modification du codage entraînera d'autres problèmes si certains caractères souhaités ne peuvent pas être codés dans le nouveau jeu de caractères.
CONVERT(expr USING transcoding_name)
character_set_connection
character_set_client
Modifiez les encodages de l'une (ou des deux) des chaînes afin qu'elles soient toutes les deux identiques et modifiez une chaîne pour utiliser le
_bin
classement approprié .Les méthodes de modification des codages et des classements ont été détaillées ci-dessus. Cette approche serait de peu d'utilité si l'on avait réellement besoin d'appliquer des règles de classement plus avancées que celles proposées par le
_bin
classement.la source
Ajout de mon 2c à la discussion pour les futurs googleurs.
J'examinais un problème similaire où j'ai obtenu l'erreur suivante lors de l'utilisation de fonctions personnalisées qui ont reçu un paramètre varchar:
En utilisant la requête suivante:
J'ai pu dire que la base de données utilisait utf8_general_ci , tandis que les tables étaient définies en utilisant utf8_unicode_ci :
Notez que les vues ont un classement NULL . Il semble que les vues et les fonctions ont des définitions de classement même si cette requête affiche null pour une vue. Le classement utilisé est le classement DB qui a été défini lors de la création de la vue / fonction.
La triste solution était à la fois de modifier le classement db et de recréer les vues / fonctions pour les forcer à utiliser le classement actuel.
Modification du classement de la base de données:
Modification du classement de table:
J'espère que cela aidera quelqu'un.
la source
show full columns from my_table;
alter table <TABLE> modify column <COL> varchar(255) collate utf8_general_ci;
SHOW session variables like '%collation%';
vous dit que »collation_connection« est »utf8mb4_general_ci«? Exécutez ensuiteSET collation_connection = utf8mb4_unicode_ci
au préalable.Parfois, il peut être dangereux de convertir des jeux de caractères, en particulier sur des bases de données contenant d'énormes quantités de données. Je pense que la meilleure option est d'utiliser l'opérateur "binaire":
la source
J'ai eu un problème similaire, j'essayais d'utiliser la procédure FIND_IN_SET avec une variable de chaîne .
et recevait l'erreur
Réponse courte:
Pas besoin de modifier les variables collation_YYYY, ajoutez simplement le classement correct à côté de votre déclaration de variable , c'est-à-dire
Longue réponse:
J'ai d'abord vérifié les variables de classement:
Ensuite, j'ai vérifié le classement de la table:
Cela signifie que ma variable a été configurée avec le classement par défaut de utf8_general_ci alors que ma table était configurée comme utf8_unicode_ci .
En ajoutant la commande COLLATE à côté de la déclaration de variable, le classement des variables correspond au classement configuré pour la table.
la source
Vous pouvez essayer ce script , qui convertit toutes vos bases de données et tables en utf8.
la source
Solution si des littéraux sont impliqués.
J'utilise Pentaho Data Integration et je ne précise pas la syntaxe SQL. L'utilisation d'une recherche de base de données très simple a donné l'erreur "Mélange illégal de classements (cp850_general_ci, COERCIBLE) et (latin1_swedish_ci, COERCIBLE) pour l'opération '='"
Le code généré était "SELECT DATA_DATE AS latest_DATA_DATE FROM hr_cc_normalised_data_date_v WHERE PSEUDO_KEY =?"
Pour faire court, la recherche était une vue et quand j'ai émis
ce qui explique d'où vient le 'cp850_general_ci'.
La vue a été simplement créée avec 'SELECT' X ', ......' Selon le manuel, les littéraux comme celui-ci devraient hériter leur jeu de caractères et leur classement des paramètres du serveur qui ont été correctement définis comme 'latin1' et 'latin1_general_cs' comme ceci clairement ne s'est pas produit, je l'ai forcé dans la création de la vue
maintenant, il affiche latin1_general_cs pour les deux colonnes et l'erreur a disparu. :)
la source
MySQL n'aime vraiment pas mélanger les classements à moins qu'il ne puisse les contraindre au même (ce qui n'est clairement pas faisable dans votre cas). Ne pouvez-vous pas simplement forcer le même classement à être utilisé via une clause COLLATE ? (ou le
BINARY
raccourci le plus simple le cas échéant ...).la source
Si les colonnes avec lesquelles vous rencontrez des problèmes sont des "hachages", considérez ce qui suit ...
Si le "hachage" est une chaîne binaire, vous devez vraiment utiliser le
BINARY(...)
type de données.Si le "hachage" est une chaîne hexadécimale, vous n'avez pas besoin d'utf8, et vous devriez éviter cela à cause des vérifications de caractères, etc. Par exemple, MySQL
MD5(...)
produit une chaîne hexadécimale de 32 octets de longueur fixe.SHA1(...)
donne une chaîne hexadécimale de 40 octets. Cela pourrait être stocké dansCHAR(32) CHARACTER SET ascii
(ou 40 pour sha1).Ou, mieux encore, stocker
UNHEX(MD5(...))
dansBINARY(16)
. Cela réduit de moitié la taille de la colonne. (Cela le rend cependant peu imprimable.)SELECT HEX(hash) ...
Si vous voulez qu'il soit lisible.La comparaison de deux
BINARY
colonnes n'a aucun problème de classement.la source
Très intéressant ... Maintenant, soyez prêt. J'ai regardé toutes les solutions «ajouter collation» et pour moi, ce sont des correctifs de pansement. La réalité est que la conception de la base de données était "mauvaise". Oui, des changements standard et de nouvelles choses sont ajoutés, bla bla, mais cela ne change pas le fait de la mauvaise conception de la base de données. Je refuse de suivre la voie de l'ajout de "collation" partout dans les instructions SQL juste pour que ma requête fonctionne. La seule solution qui fonctionne pour moi et éliminera pratiquement la nécessité de modifier mon code à l'avenir est de repenser la base de données / tables pour correspondre au jeu de caractères avec lequel je vivrai et que j'adopterai à long terme. Dans ce cas, j'ai choisi de choisir le jeu de caractères " utf8mb4 ".
Ainsi, la solution ici lorsque vous rencontrez ce message d'erreur "illégal" consiste à reconcevoir votre base de données et vos tables. C'est beaucoup plus facile et plus rapide que ça. L'exportation de vos données et leur réimportation à partir d'un CSV peuvent même ne pas être nécessaires. Modifiez le jeu de caractères de la base de données et assurez-vous que tous les jeux de caractères de vos tables correspondent.
Utilisez ces commandes pour vous guider:
Maintenant, si vous aimez ajouter "assembler" ici et là et renforcer votre code avec des "remplacements" forcés, soyez ma conjecture.
la source
Une solution possible consiste à convertir l'intégralité de la base de données en UTF8 (voir également cette question ).
la source
Une autre source du problème avec les classements est la
mysql.proc
table. Vérifiez les classements de vos procédures et fonctions de stockage:Faites également attention aux colonnes
mysql.proc.collation_connection
etmysql.proc.character_set_client
.la source
Si vous avez installé phpMyAdmin, vous pouvez suivre les instructions fournies dans le lien suivant: https://mediatemple.net/community/products/dv/204403914/default-mysql-character-set-and-collation Vous devez faire correspondre l'assemblage de la base de données avec celle de toutes les tables, ainsi que les champs des tables, puis recompiler toutes les procédures et fonctions stockées. Avec cela, tout devrait fonctionner à nouveau.
la source
J'ai utilisé
ALTER DATABASE mydb DEFAULT COLLATE utf8_unicode_ci;
, mais n'a pas fonctionné.Dans cette requête:
Ce travail pour moi:
Oui, seulement a
concat
.la source
Ce code doit être placé dans Run SQL query / queries on database
FENÊTRE DE QUESTION SQL
Veuillez remplacer table_name et column_name par le nom approprié.
la source