Устранение неполадок «Недопустимое сочетание параметров сортировки» в MySQL - PullRequest
181 голосов
/ 12 июня 2010

При попытке выполнить выборку с помощью хранимой процедуры в MySQL выдается следующее сообщение:

Недопустимое сочетание параметров сортировки (latin1_general_cs, IMPLICIT) и (latin1_general_ci, IMPLICIT) для операции '='

Есть идеи о том, что здесь может пойти не так?

Параметры сортировки таблицы: latin1_general_ci, а столбца в предложении where - latin1_general_cs. * 1011.*

Ответы [ 13 ]

188 голосов
/ 12 июня 2010

Обычно это вызвано сравнением двух строк несовместимого сопоставления или попыткой выделить данные другого сопоставления в объединенный столбец.

В предложении COLLATE можно указать сопоставление, используемое в запросе.

Например, следующее предложение WHERE всегда будет содержать опубликованную вами ошибку:

WHERE 'A' COLLATE latin1_general_ci = 'A' COLLATE latin1_general_cs

Ваше решение состоит в том, чтобы указать общее сопоставление для двух столбцов в запросе.Вот пример, который использует предложение COLLATE:

SELECT * FROM table ORDER BY key COLLATE latin1_general_ci;

Другой вариант - использование оператора BINARY:

BINARY str - сокращение от CAST (strAS BINARY).

Ваше решение может выглядеть примерно так:

SELECT * FROM table WHERE BINARY a = BINARY b;

или

SELECT * FROM table ORDER BY BINARY a;
136 голосов
/ 11 января 2014

TL; DR

Либо измените параметры сортировки одной (или обеих) строк так, чтобы они совпадали, либо добавьте в выражение выражение COLLATE.


  1. Что это за штука с "сопоставлением"?

    Как описано в разделе Наборы символов и сопоставления в целом :

    A набор символов - это набор символов и кодировок. сопоставление - это набор правил для сравнения символов в наборе символов.Давайте проясним это различие на примере воображаемого набора символов.

    Предположим, что у нас есть алфавит из четырех букв: «A», «B», «a», «b».Каждой букве присваивается число: «A» = 0, «B» = 1, «a» = 2, «b» = 3. Буква «A» является символом,число 0 - это кодировка для «A», а комбинация всех четырех букв и их кодировок - набор символов .

    Предположим, что мы хотим сравнить два строковых значения: «A» и «B».Самый простой способ сделать это - посмотреть на кодировки: 0 для «A» и 1 для «B».Поскольку 0 меньше 1, мы говорим «A» меньше «B».Мы только что применили сопоставление к нашему набору символов.Сортировка - это набор правил (в данном случае только одно правило): «сравни кодировки». Мы называем это самое простое из всех возможных сопоставлений двоичное сопоставление.

    Но что если мыхотите сказать, что строчные и прописные буквы эквивалентны?Тогда у нас было бы как минимум два правила: (1) обрабатывать строчные буквы «a» и «b» как «A» и «B»;(2) затем сравните кодировки.Мы называем это регистронезависимым сопоставлением.Это немного сложнее, чем двоичное сопоставление.

    В реальной жизни большинство наборов символов имеют много символов: не только «A» и «B», но и целые алфавиты, иногда несколько алфавитов или восточныесистемы письма с тысячами символов, наряду со многими специальными символами и знаками препинания.Кроме того, в реальной жизни большинство сопоставлений имеют много правил, не только для того, чтобы различать буквы, но также и для того, чтобы различать акценты («акцент» - это знак, прикрепленный к символу, как в немецком «Ö»), и длямногосимвольные сопоставления (например, правило «Ö» = «OE» в одном из двух немецких сопоставлений).

    Дополнительные примеры приведены в разделе ПримерыЭффект сопоставления .

  2. Хорошо, но как MySQL решает, какое сопоставление использовать для данного выражения?

    Как указано в Сборка выражений :

    В подавляющем большинстве операторов очевидно, что MySQL использует сопоставление для разрешения операции сравнения.Например, в следующих случаях должно быть ясно, что сопоставление - это сопоставление столбца charset_name:

    SELECT x FROM T ORDER BY x;
    SELECT x FROM T WHERE x = x;
    SELECT DISTINCT x FROM T;
    

    Однако с несколькими операндами может быть неоднозначность.Например:

    SELECT x FROM T WHERE x = 'Y';
    

    Должно ли сравнение использовать сопоставление столбца x или строкового литерала 'Y'?И у x, и у 'Y' есть параметры сортировки, поэтому какое сопоставление имеет приоритет?

    Стандартный SQL решает такие вопросы, используя то, что раньше называлось правилами "согласованности".

    [ <strong><em>deletia</em></strong> ]

    MySQL используетзначения разрешимости со следующими правилами для устранения неоднозначностей:

    • Используйте сопоставление с наименьшим значением сопоставимости.

    • Если обе стороны имеют одинаковую сопоставимость, тогда:

      • Если обе стороны Unicode или обе стороны не Unicode, это ошибка.

      • Если одна из сторонимеет набор символов Unicode, а другая сторона имеет набор символов не-Unicode,сторона с набором символов Unicode выигрывает, и автоматическое преобразование набора символов применяется к стороне не-Unicode.Например, следующий оператор не возвращает ошибку:

        SELECT CONCAT(utf8_column, latin1_column) FROM t1;
        

        Он возвращает результат с набором символов utf8 и таким же сопоставлением, что и utf8_column.Значения latin1_column автоматически преобразуются в utf8 перед объединением.

      • Для операции с операндами из того же набора символов, но которые смешивают параметры сортировки _bin и _ciили _cs, используется _bin.Это похоже на то, как операции, которые смешивают недвоичные и двоичные строки, оценивают операнды как двоичные строки, за исключением того, что они используются для сопоставлений, а не типов данных.

  3. Так что же такое «недопустимое сочетание параметров сортировки»?

    «Недопустимое сочетание параметров сортировки» возникает, когда выражение сравнивает две строки разных параметров сортировки, но одинаковыхпринуждение и правила принуждения не могут помочь разрешить конфликт.Это ситуация, описанная в третьем пункте в приведенной выше цитате.

    Конкретная ошибка, приведенная в вопросе Illegal mix of collations (latin1_general_cs,IMPLICIT) and (latin1_general_ci,IMPLICIT) for operation '=', говорит нам о том, что было проведено сравнение на равенство между двумя не-Unicode-строками одинаковогосжимаемость.Кроме того, это говорит нам о том, что параметры сортировки не были даны явно в выражении, а скорее подразумевались из источников строк (таких как метаданные столбцов).

  4. Это все очень хорошо,но как устранить такие ошибки?

    Как следует из приведенных выше выдержек из руководства, эту проблему можно решить несколькими способами, два из которых целесообразны и рекомендуются:

    • Измените параметры сортировки одной (или обеих) строк таким образом, чтобы они соответствовали друг другу, и двусмысленности больше не было.

      Как это можно сделать, зависит ототкуда пришла строка: буквальные выражения принимают параметры сортировки, указанные в системной переменной collation_connection;значения из таблиц принимают параметры сортировки, указанные в метаданных их столбцов.

    • Принудительное использование одной строки не принудительно.

      Я опустил следующую цитату извыше:

      MySQL назначает значения принудительности следующим образом:

      • Явное предложение COLLATE имеет принудительную настройку 0. (вообще не принудительно).

      • Конкатенация двух строк с различными параметрами сортировки имеет коэрцитивность 1.

      • Параметры сортировки столбца или хранимого стандартного параметра или локальногопеременная имеет коэрцитивность 2.

      • «системная константа» (строка, возвращаемая такими функциями, как USER() или VERSION()) имеет совокупность 3 *. 1201 *

      • сопоставление литерала имеет коэффициент принудительности 4.

      • NULL или выражение, котороеявляется производным от NULL и имеет принуждение 5.

      Таким образом, просто добавив COLLATE clauИспользование одной из строк, используемых в сравнении, приведет к принудительному использованию этого сопоставления.

    В то время как другие будут ужасно плохой практикой, если они будут развернуты просто для устранения этой ошибки:

    • Заставить одну (или обе) строки иметь другое значение принудительности, чтобы иметь приоритет.

      Использование CONCAT() или CONCAT_WS() приведет к строке с принудительным значением 1;и (если в хранимой подпрограмме) использование параметров / локальных переменных приведет к появлению строк с принудительным значением 2.

    • Изменение кодировки одного (или обоих) изСтроки, так что один Unicode, а другой нет.

      Это можно сделать с помощью транскодирования с CONVERT(<em>expr</em> USING <em>transcoding_name</em>); или путем изменения базового набора символов данных (например, изменение столбца, изменение character_set_connection для литеральных значений или отправка их от клиента в другой кодировке и изменение character_set_client / добавление вводного набора символов). Обратите внимание, что изменение кодировки приведет к другим проблемам, если некоторые новые символы не могут быть закодированы в новом наборе символов.

    • Измените кодировки одной (или обеих) строк так, чтобы они были одинаковыми, и измените одну строку, чтобы использовать соответствующее сопоставление _bin.

      Методы изменения кодировок и параметров сортировки были подробно описаны выше. Этот подход был бы бесполезен, если на самом деле нужно применять более сложные правила сопоставления, чем те, которые предлагаются в _bin.

55 голосов
/ 24 июня 2012

Добавление моего 2c в обсуждение будущих гуглеров.

Я исследовал похожую проблему, в которой я получил следующую ошибку при использовании пользовательских функций , которые получили параметр varchar:

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

Используя следующий запрос:

mysql> show variables like "collation_database";
    +--------------------+-----------------+
    | Variable_name      | Value           |
    +--------------------+-----------------+
    | collation_database | utf8_general_ci |
    +--------------------+-----------------+

Я смог сказать, что БД использовала utf8_general_ci , тогда как таблицы были определены с помощью utf8_unicode_ci :

mysql> show table status;
    +--------------+-----------------+
    | Name         | Collation       |
    +--------------+-----------------+
    | my_view      | NULL            |
    | my_table     | utf8_unicode_ci |
    ...

Обратите внимание, что представления имеют сопоставление NULL .Похоже, что представления и функции имеют определения параметров сортировки, даже если этот запрос показывает нулевое значение для одного представления.Используемая сортировка - это сортировка БД, которая была определена при создании представления / функции.

Печальным решением было изменить сортировку БД и воссоздать представления / функции, чтобы заставить их использовать текущую сортировку.

  • Изменение параметров сортировки БД:

    ALTER DATABASE mydb DEFAULT COLLATE utf8_unicode_ci;
    

Надеюсь, это кому-нибудь поможет.

13 голосов
/ 24 ноября 2012

Иногда преобразование кодировок может быть опасным, особенно в базах данных с огромными объемами данных. Я думаю, что лучший вариант - использовать «двоичный» оператор:

e.g : WHERE binary table1.column1 = binary table2.column1
7 голосов
/ 10 октября 2017

У меня была похожая проблема, я пытался использовать процедуру FIND_IN_SET со строкой переменная .

SET @my_var = 'string1,string2';
SELECT * from my_table WHERE FIND_IN_SET(column_name,@my_var);

и получал ошибку

Код ошибки: 1267. Неверное сочетание параметров сортировки (utf8_unicode_ci, IMPLICIT) и (utf8_general_ci, IMPLICIT) для операции 'find_in_set'

Краткий ответ:

Нет необходимости изменять какие-либо переменные collation_YYYY, просто добавьте правильное сопоставление рядом с объявлением переменной , т.е.

SET @my_var = 'string1,string2' COLLATE utf8_unicode_ci;
SELECT * from my_table WHERE FIND_IN_SET(column_name,@my_var);

Длинный ответ:

Сначала я проверил параметры сортировки:

mysql> SHOW VARIABLES LIKE 'collation%';
    +----------------------+-----------------+
    | Variable_name        | Value           |
    +----------------------+-----------------+
    | collation_connection | utf8_general_ci |
    +----------------------+-----------------+
    | collation_database   | utf8_general_ci |
    +----------------------+-----------------+
    | collation_server     | utf8_general_ci |
    +----------------------+-----------------+

Затем я проверил сопоставление таблицы:

mysql> SHOW CREATE TABLE my_table;

CREATE TABLE `my_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `column_name` varchar(40) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=125 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Это означает, что моя переменная была настроена с параметрами сортировки по умолчанию utf8_general_ci , а моя таблица была настроена как utf8_unicode_ci .

Добавив команду COLLATE рядом с объявлением переменной, переменная сопоставления совпадает с сопоставлением, настроенным для таблицы.

5 голосов
/ 13 декабря 2012

Вы можете попробовать этот скрипт , который преобразует все ваши базы данных и таблицы в utf8.

2 голосов
/ 20 октября 2015

Решение, если задействованы литералы.

Я использую интеграцию данных Pentaho и не могу указать синтаксис sql. Использование очень простого поиска БД дало ошибку "Недопустимое сочетание параметров сортировки (cp850_general_ci, COERCIBLE) и (latin1_swedish_ci, COERCIBLE) для операции '='"

Сгенерированный код был "ВЫБЕРИТЕ DATA_DATE AS latest_DATA_DATE ОТ hr_cc_normalised_data_date_v ГДЕ PSEUDO_KEY =?"

Если коротко, история была просмотрена, и когда я выпустил

mysql> show full columns from hr_cc_normalised_data_date_v;
+------------+------------+-------------------+------+-----+
| Field      | Type       | Collation         | Null | Key |
+------------+------------+-------------------+------+-----+
| PSEUDO_KEY | varchar(1) | cp850_general_ci  | NO   |     |
| DATA_DATE  | varchar(8) | latin1_general_cs | YES  |     |
+------------+------------+-------------------+------+-----+

, который объясняет, откуда взялся cp850_general_ci.

Представление было просто создано с помощью SELECT X, ...... В соответствии с подобными инструкциями, ручные литералы должны наследовать свой набор символов и параметры сортировки от настроек сервера, которые были правильно определены как 'latin1' и 'latin1_general_cs' поскольку этого явно не произошло, я заставил его создать представление

CREATE OR REPLACE VIEW hr_cc_normalised_data_date_v AS
SELECT convert('X' using latin1) COLLATE latin1_general_cs        AS PSEUDO_KEY
    ,  DATA_DATE
FROM HR_COSTCENTRE_NORMALISED_mV
LIMIT 1;

теперь он показывает latin1_general_cs для обоих столбцов, и ошибка исчезла. :)

1 голос
/ 22 декабря 2015

Если столбцы, с которыми у вас возникают проблемы, являются "хешами", рассмотрите следующее ...

Если "хэш" является двоичной строкой, вам действительно следует использовать BINARY(...) тип данных.

Если "хеш" - это шестнадцатеричная строка, вам не нужен utf8, и вам следует избегать этого из-за проверок символов и т. Д. Например, MySQL MD5(...) возвращает 32-байтовую шестнадцатеричную строку фиксированной длины. SHA1(...) дает 40-байтовую шестнадцатеричную строку. Это может быть сохранено в CHAR(32) CHARACTER SET ascii (или 40 для sha1).

Или, что еще лучше, сохраните UNHEX(MD5(...)) в BINARY(16). Это сокращает вдвое размер столбца. (Однако, это делает его довольно непечатным.) SELECT HEX(hash) ..., если вы хотите, чтобы он читался.

Сравнение двух столбцов BINARY не имеет проблем с сопоставлением.

1 голос
/ 12 июня 2010

MySQL действительно не любит смешивать параметры сортировки, если только он не может привести их к одному и тому же (что в вашем случае явно невозможно)Разве вы не можете принудительно использовать одно и то же сопоставление с помощью предложения COLLATE ?(или более простой BINARY ярлык, если применимо ...).

0 голосов
/ 13 октября 2017

Этот код необходимо поместить внутрь Запуска SQL-запросов / запросов к базе данных

SQL QUERY WINDOW

ALTER TABLE `table_name` CHANGE `column_name` `column_name`   VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL;

Пожалуйста, замените table_name и column_name на соответствующее имя.

...