Устранение ошибки «Неверное смешение параметров сортировки» в MySQL

211

Я получаю сообщение об ошибке ниже при попытке сделать выбор через хранимую процедуру в MySQL.

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

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

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

user355562
источник
2
Я использовал различные базы данных в течение больших периодов (с 1990 года), и использование сопоставления и принудительной обработки, сделанное NySQL, выглядит как «сумасшедший», базы данных решают проблемы, накладывая «ОДИН» набор символов для базы данных, затем до процедуры импорта / экспорта для преобразования из / в уникальный набор символов, используемый базой данных. Решение Mysql choosen является разрушительным, потому что смешивает «проблемы приложения» (преобразование набора символов) с проблемой базы данных (использование сопоставления). Почему бы не «удалить» эти глупые и громоздкие функции из базы данных, чтобы она стала намного более удобной и управляемой
Маурицио Пиевайоли

Ответы:

216

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

Предложение 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 (str AS BINARY).

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

SELECT * FROM table WHERE BINARY a = BINARY b;

или,

SELECT * FROM table ORDER BY BINARY a;
определяет
источник
2
Спасибо. На самом деле, в моем случае это выглядит довольно странно. Когда я запускаю запрос как есть, через браузер запросов он получает результаты. Но использование хранимой процедуры выдает ошибку.
user355562
5
Двоичный файл казался мне лучшим решением. Это может быть лучше для вас, если вы не используете хитрые фильтры.
Адам Ф
У меня та же самая проблема, способ, которым я решаю эту проблему, воссоздает с самого начала. Я попытался изменить параметры сортировки, но когда я все-таки присоединился, все еще получала ошибку, поэтому я попытался таким образом. cmiiw
Бобби Z
Обратите внимание, что в MariaDB используется ошибка, COLLATE latin1_general_ci которая вызывает еще одну ошибку: COLLATION 'utf8_general_ci' is not valid for CHARACTER SET 'latin1''- даже если у вас нет столбца с CHARACTER SET 'latin1'! Решением является использование BINARY cast. Смотрите также этот вопрос
Mel_T
154

TL; DR

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


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

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

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

    Предположим, что у нас есть алфавит с четырьмя буквами: « 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 решает такие вопросы, используя то, что раньше называлось правилами «принуждения».

    [ делеция ]

    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.

      • Сопоставление литерала имеет принуждение 4.

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

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

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

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

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

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

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

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

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

eggyal
источник
4
Обратите внимание, что «недопустимое сочетание параметров сортировки» может также возникать, когда нет двусмысленности относительно того, какой порядок сортировки следует использовать, но строка, которая должна быть приведена, должна быть перекодирована в кодировку, в которой некоторые из ее символов не могут быть представлены. Я обсуждал этот случай в предыдущем ответе .
eggyal
5
Отличный ответ. Этот должен быть дальше, потому что он погружается в то, что разработчики должны знать; не только как это исправить, но и понять, почему все происходит так, как оно происходит.
отметьте
Спасибо, чувак, ты научил меня чему-то сегодня.
Брианкип
67

Добавляю свой 2с к обсуждению для будущих гуглеров.

Я исследовал похожую проблему, в которой я получил следующую ошибку при использовании пользовательских функций, которые получили параметр 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;
  • Изменение таблицы сортировки:

    ALTER TABLE mydb CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

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

Ариэль Т
источник
12
Сортировка также может быть установлена ​​на уровне столбца. Вы можете просмотреть это с:show full columns from my_table;
Джонатан Тран
Спасибо. Я просто отбросил схему, воссоздал ее с правильным сопоставлением по умолчанию и заново импортировал все.
JRun
1
@JonathanTran Спасибо! У меня был набор символов и сопоставление для всех таблиц, базы данных и соединения, но это все равно давало ошибку! Сортировка не была установлена ​​на столбце! Я исправил это сalter table <TABLE> modify column <COL> varchar(255) collate utf8_general_ci;
Хлоя
2
Sidenote для будущих Google: даже если ваша база данных, таблицы и поля имеют одинаковое сопоставление, вы также должны убедиться, что ваше соединение использует то же сопоставление. Все имеет »utf8mb4_unicode_ci«, но SHOW session variables like '%collation%';говорит вам, что »collation_connection« есть »utf8mb4_general_ci«? Тогда беги SET collation_connection = utf8mb4_unicode_ciзаранее.
pixelbrackets
Спасибо! Мне понадобилось время, чтобы выследить это. Таблицы должны быть не только одинаковыми, но и БД!
мото
15

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

e.g : WHERE binary table1.column1 = binary table2.column1
Джастин Винсент
источник
10

У меня была похожая проблема, я пытался использовать процедуру 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 рядом с объявлением переменной, переменная сопоставления совпала с сопоставлением, настроенным для таблицы.

nkatsar
источник
5

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

Мират Кан Байрак
источник
1
строка 24 «cur» вместо «курсора»
RTOSkit
2
И утраивает размер некоторых индексов.
Дамиан Йеррик
2

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

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

Сгенерированный код был «ВЫБЕРИТЕ DATA_DATE AS latest_DATA_DATE FROM hr_cc_normalised_data_date_v WHERE 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 для обоих столбцов, и ошибка исчезла. :)

jc508
источник
1

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

Алекс Мартелли
источник
Это уникально для MySQL? Как другие системы обрабатывают смесь несовместимых параметров сортировки с равным приоритетом?
eggyal
Ваша ссылка недействительна.
Benubird
1

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

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

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

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

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

Рик Джеймс
источник
1

Очень интересно ... Теперь будьте готовы. Я посмотрел на все решения "add collate", и для меня это исправления бинтов. Реальность такова, что дизайн базы данных был «плохим». Да, стандартные изменения и новые вещи добавляются, бла-бла, но это не меняет факт проектирования плохой базы данных. Я отказываюсь идти по пути добавления «сортировки» по всем операторам SQL, чтобы заставить мой запрос работать. Единственное решение, которое работает для меня и фактически устранит необходимость подправлять мой код в будущем, - это изменить дизайн базы данных / таблиц в соответствии с набором символов, с которым я буду жить и в будущем. В этом случае я выбираю набор символов « utf8mb4 ».

Таким образом, решение, когда вы сталкиваетесь с этим «недопустимым» сообщением об ошибке, состоит в том, чтобы изменить дизайн базы данных и таблиц. Это намного проще и быстрее, чем кажется. Экспорт ваших данных и повторный импорт из CSV может даже не потребоваться. Измените набор символов базы данных и убедитесь, что все наборы символов ваших таблиц совпадают.

Используйте эти команды, чтобы направлять вас:

SHOW VARIABLES LIKE "collation_database";
SHOW TABLE STATUS;

Теперь, если вам нравится добавлять «сортировать» здесь и там и дополнять свой код с помощью «переопределений» полных сил, то я думаю.

Ня Нгуен
источник
0

Еще одним источником проблемы с сопоставлениями является mysql.procтаблица. Проверьте подборки ваших процедур хранения и функций:

SELECT
  p.db, p.db_collation, p.type, COUNT(*) cnt
FROM mysql.proc p
GROUP BY p.db, p.db_collation, p.type;

Также обратите внимание mysql.proc.collation_connectionи на mysql.proc.character_set_clientколонки.

Рувим
источник
0

Если у вас есть PHPMYADMIN установлен, вы можете следовать инструкциям , приведенным в следующей ссылке: https://mediatemple.net/community/products/dv/204403914/default-mysql-character-set-and-collation Вы должны соответствовать Сливать базы данных с этим из всех таблиц, а также полей таблиц, а затем перекомпилировать все хранимые процедуры и функции. С этим все должно работать снова.

Мануэль Эмилио Варгас Эррера
источник
-1

Я использовал ALTER DATABASE mydb DEFAULT COLLATE utf8_unicode_ci;, но не работал.

В этом запросе:

Select * from table1, table2 where table1.field = date_format(table2.field,'%H');

Эта работа для меня:

Select * from table1, table2 where concat(table1.field) = date_format(table2.field,'%H');

Да, только concat.

Knito Auron
источник
Проверьте параметры сортировки ваших таблиц и их столбцов (показать статус таблицы; и показать полные столбцы из таблицы 1;). Использование alter database не сработает, если таблицы уже созданы с неправильным сопоставлением.
Ариэль Т
ALTER DATABASE mydb DEFAULT COLLATE ... работает для меня, так что upvote. Возможно, у меня было преимущество, так как я мог удалить и воссоздать базу данных и загрузить из резервных копий.
Tobixen
-2

Этот код должен быть помещен внутри Запустить 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 на соответствующее имя.

Sukumar
источник