Mysql
 sql >> база данни >  >> RDS >> Mysql

MySQL Незаконен микс от съпоставяния

Полезно е да се разберат следните дефиниции:

  • Кодиране на знаци подробности как всеки символ е представен в двоичен вид (и следователно се съхранява в компютъра). Например символът é (U+00E9, латинската малка буква E с остър знак) е кодирана като 0xc3a9 в UTF-8 (който MySQL нарича utf8 ) и 0xe9 в Windows-1252 (който MySQL нарича latin1 ).

  • набор от знаци е азбуката на символите, които могат да бъдат представени с помощта на дадено кодиране на знаци. Объркващо, терминът също се използва за означаване на същото като кодирането на знаци.

  • Аколекция е подреждане на набор от знаци, така че низовете да могат да се сравняват. Например:latin1_swedish_ci на MySQL съпоставянето третира повечето акцентирани вариации на символ като еквивалентни на основния знак, докато неговият latin1_general_ci съпоставянето ще ги подреди преди следващия основен знак, но не е еквивалентно (има и други, по-значими разлики:като например реда на знаците като å , ä , ö и ß ).

MySQL ще реши кое съпоставяне трябва да се приложи към даден израз, както е документирано под Колекция от изрази :по-специално, сортирането на колона има предимство пред това на низовия литерал.

WHERE клауза на вашата заявка сравнява следните низове:

  1. стойност в fos_user.username , кодиран в набора от знаци на колоната (Windows-1252) и изразяващ предпочитание за нейното съпоставяне latin1_swedish_ci (със стойност на принуждаемостта 2); с

  2. низовия литерал 'Nrv⧧Kasi' , кодиран в набора от знаци на връзката (UTF-8, както е конфигуриран от Doctrine) и изразяващ предпочитание за съпоставянето на връзката utf8_general_ci (със стойност на принуждаемостта 4).

Тъй като първият от тези низове има по-ниска стойност на коерцибилност от втория, MySQL се опитва да извърши сравнението, използвайки съпоставянето на този низ:latin1_swedish_ci . За да направи това, MySQL се опитва да преобразува втория низ в latin1 — но тъй като знак не съществува в този набор от знаци, сравнението е неуспешно.

Предупреждение

Човек трябва да спре за момент, за да помисли как колоната е кодирана в момента:опитвате се да филтрирате за записи, където fos_user.username е равно на низ, който съдържа знак, който не може съществуват в тази колона !

Ако смятате, че колоната прави съдържат такива знаци, тогава вероятно сте писали в колоната, докато кодирането на символите за връзка е било зададено на нещо (напр. latin1 ), което накара MySQL да интерпретира получената последователност от байтове като знаци, които всички са в набора от символи на Windows-1252.

Ако случаят е такъв, преди да продължите, трябва да коригирате данните си!

  1. преобразувайте такива колони в кодирането на знаци, което е било използвано при вмъкване на данни, ако е различно от съществуващото кодиране:

    ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET foo;
    
  2. махнете информацията за кодиране, свързана с такива колони, като ги преобразувате в binary набор от символи:

    ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET binary;
    
  3. асоциирайте с такива колони кодирането, в което действително са били предадени данните, като ги преобразувате в съответния набор от знаци.

    ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET bar;
    

Имайте предвид, че ако преобразувате от многобайтово кодиране, може да се наложи да увеличите размера на колоната (или дори да промените нейния тип), за да поберете максималната възможна дължина на конвертирания низ.

След като човек се увери, че колоните са правилно кодирани, може да принуди сравнението да се извърши с помощта на съпоставяне на Unicode чрез едно от другото—

  • изрично преобразуване на стойността fos_user.username към набор от символи Unicode:

    WHERE CONVERT(fos_user.username USING utf8) = ?
    
  • принуждаването на низовия литерал да има по-ниска стойност на принуждаемост от колоната (ще доведе до имплицитно преобразуване на стойността на колоната в UTF-8):

    WHERE fos_user.username = ? COLLATE utf8_general_ci
    

Или, както казвате, може да се преобразува за постоянно колоната(ите) в Unicode кодиране и да се зададе подходящо съпоставяне.

Принципното съображение е, че кодирането на Unicode заема повече място от еднобайтови набори от знаци, така че:

  • може да се наложи повече място за съхранение;

  • сравненията може да са по-бавни; и

  • Може да се наложи коригиране на дължината на индексния префикс (имайте предвид, че максимумът е в байтове, така че може да представлява по-малко знаци от преди).

Също така имайте предвид, че както е документирано под ALTER TABLE Синтаксис :



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PHP / PDO :SQL за намиране на ред, който съдържа стойност на низ

  2. Разбиране на изгледите в SQL

  3. Актуализирайте и изберете в една заявка

  4. Извличане на най-новата бележка (по времева марка) в една заявка от таблица 1:n

  5. Версията на Django MySQLdb не съвпада с версията на _mysql Ubuntu