sql >> Databasteknik >  >> RDS >> Mysql

MySQL Olaglig blandning av kollationer

Det är bra att förstå följande definitioner:

  • En teckenkodning detaljer hur varje symbol representeras binärt (och därför lagras i datorn). Till exempel symbolen é (U+00E9, latin liten bokstav E med akut) är kodad som 0xc3a9 i UTF-8 (som MySQL kallar utf8 ) och 0xe9 i Windows-1252 (som MySQL kallar latin1 ).

  • En teckenuppsättning är alfabetet av symboler som kan representeras med en given teckenkodning. Förvirrande nog används termen också för att betyda samma som teckenkodning.

  • En sortering är en ordning på en teckenuppsättning, så att strängar kan jämföras. Till exempel:MySQL:s latin1_swedish_ci sortering behandlar de flesta accentvarianter av ett tecken som likvärdiga med basteckenet, medan dess latin1_general_ci sortering kommer att ordna dem före nästa bastecken men inte likvärdiga (det finns andra, mer signifikanta, skillnader också:som ordningen på tecken som å , ä , ö och ß ).

MySQL kommer att avgöra vilken sortering som ska tillämpas på ett givet uttryck enligt dokumentationen under Samling av uttryck :i synnerhet har sammanställningen av en kolumn företräde framför den för en bokstavlig sträng.

WHERE satsen i din fråga jämför följande strängar:

  1. ett värde i fos_user.username , kodad i kolumnens teckenuppsättning (Windows-1252) och uttrycker en preferens för dess sortering latin1_swedish_ci (med ett tvångsvärde på 2); med

  2. strängen bokstavlig 'Nrv⧧Kasi' , kodad i anslutningens teckenuppsättning (UTF-8, som konfigurerats av Doctrine) och uttrycker en preferens för anslutningens sammanställning utf8_general_ci (med ett tvångsvärde på 4).

Eftersom den första av dessa strängar har ett lägre tvångsvärde än den andra, försöker MySQL att utföra jämförelsen med den strängens sammanställning:latin1_swedish_ci . För att göra det försöker MySQL konvertera den andra strängen till latin1 —men eftersom tecken inte finns i den teckenuppsättningen misslyckas jämförelsen.

Varning

Man bör pausa ett ögonblick för att överväga hur kolumnen för närvarande är kodad:du försöker filtrera efter poster där fos_user.username är lika med en sträng som innehåller ett tecken som inte kan finns i den kolumnen !

Om du tror att kolumnen gör innehåller sådana tecken, då skrev du förmodligen till kolumnen medan kopplingsteckenkodningen var inställd på något (t.ex. latin1 ) som fick MySQL att tolka den mottagna bytesekvensen som tecken som alla finns i Windows-1252-teckenuppsättningen.

Om så är fallet bör du åtgärda dina data innan du fortsätter!

  1. konvertera sådana kolumner till teckenkodningen som användes vid datainfogning, om den skiljer sig från den befintliga kodningen:

    ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET foo;
    
  2. släpp kodningsinformationen som är associerad med sådana kolumner genom att konvertera dem till binary teckenuppsättning:

    ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET binary;
    
  3. associera med sådana kolumner kodningen i vilken data faktiskt överfördes genom att konvertera dem till relevant teckenuppsättning.

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

Observera att om du konverterar från en multi-byte-kodning, kan du behöva öka storleken på kolumnen (eller till och med ändra dess typ) för att ta emot den maximalt möjliga längden på den konverterade strängen.

När man väl är säker på att kolumnerna är korrekt kodade kan man tvinga jämförelsen att utföras med hjälp av en Unicode-kollation genom att antingen—

  • explicit konvertera värdet fos_user.username till en Unicode-teckenuppsättning:

    WHERE CONVERT(fos_user.username USING utf8) = ?
    
  • tvingar strängen literal att ha ett lägre tvångsvärde än kolumnen (kommer att orsaka en implicit konvertering av kolumnens värde till UTF-8):

    WHERE fos_user.username = ? COLLATE utf8_general_ci
    

Eller man kan, som du säger, permanent konvertera kolumn(erna) till en Unicode-kodning och ställa in dess sortering på lämpligt sätt.

Det huvudsakliga övervägandet är att Unicode-kodningar tar upp mer utrymme än teckenuppsättningar med en byte, så:

  • mer lagringsutrymme kan behövas;

  • jämförelser kan vara långsammare; och

  • Längden på indexprefixet kan behöva justeras (observera att maxvärdet är i byte, så det kan representera färre tecken än tidigare).

Tänk också på att, som dokumenterats under ALTER TABLE Syntax :



  1. mysqli_query() förväntar sig minst 2 parametrar, 1 ges in?

  2. Hur man ansluter till en avlägsen PostgreSQL-databas via SSL med Python

  3. uppdatera flera rader med limit i mysql?

  4. Hur man skapar triggers i Codeigniters migreringsbibliotek