sql >> Database >  >> RDS >> Mysql

MySQL Illegale mix van collaties

Het is handig om de volgende definities te begrijpen:

  • Een tekencodering geeft aan hoe elk symbool binair wordt weergegeven (en dus op de computer wordt opgeslagen). Bijvoorbeeld het symbool é (U+00E9, Latijnse kleine letter E met acute) is gecodeerd als 0xc3a9 in UTF-8 (die MySQL utf8 aanroept) ) en 0xe9 in Windows-1252 (die MySQL latin1 noemt ).

  • Een tekenset is het alfabet van symbolen die kunnen worden weergegeven met een bepaalde tekencodering. Verwarrend genoeg wordt de term ook gebruikt om hetzelfde te betekenen als tekencodering.

  • Een verzameling is een volgorde op een tekenset, zodat strings vergeleken kunnen worden. Bijvoorbeeld:MySQL's latin1_swedish_ci collatie behandelt de meeste variaties met accenten van een teken als equivalent aan het basisteken, terwijl de latin1_general_ci sortering plaatst ze vóór het volgende basisteken, maar niet equivalent (er zijn ook andere, meer significante verschillen:zoals de volgorde van tekens zoals å , ä , ö en ß ).

MySQL zal beslissen welke sortering moet worden toegepast op een bepaalde uitdrukking, zoals beschreven onder Verzameling van uitdrukkingen :in het bijzonder heeft de sortering van een kolom voorrang op die van een letterlijke tekenreeks.

De WHERE clausule van uw zoekopdracht vergelijkt de volgende tekenreeksen:

  1. een waarde in fos_user.username , gecodeerd in de tekenset van de kolom (Windows-1252) en een voorkeur voor de sortering ervan uitdrukken latin1_swedish_ci (met een coërcibiliteitswaarde van 2); met

  2. de letterlijke tekenreeks 'Nrv⧧Kasi' , gecodeerd in de tekenset van de verbinding (UTF-8, zoals geconfigureerd door Doctrine) en die een voorkeur uitdrukt voor de sortering van de verbinding utf8_general_ci (met een dwangwaarde van 4).

Aangezien de eerste van deze strings een lagere coercibility-waarde heeft dan de tweede, probeert MySQL de vergelijking uit te voeren met behulp van de sortering van die string:latin1_swedish_ci . Om dit te doen, probeert MySQL de tweede string te converteren naar latin1 —maar sinds de teken bestaat niet in die tekenset, de vergelijking mislukt.

Waarschuwing

Men moet even pauzeren om na te gaan hoe de kolom momenteel is gecodeerd:u probeert te filteren op records waar fos_user.username is gelijk aan een tekenreeks die een teken bevat dat niet bestaan ​​in die kolom !

Als u van mening bent dat de kolom dat wel dergelijke tekens bevatten, hebt u waarschijnlijk naar de kolom geschreven terwijl de tekencodering van de verbinding op iets was ingesteld (bijv. latin1 ) waardoor MySQL de ontvangen bytereeks interpreteerde als tekens die allemaal in de tekenset van Windows-1252 staan.

Als dit het geval is, moet u uw gegevens herstellen voordat u verder gaat!

  1. converteer dergelijke kolommen naar de tekencodering die werd gebruikt bij het invoegen van gegevens, indien verschillend van de bestaande codering:

    ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET foo;
    
  2. verwijder de coderingsinformatie die aan dergelijke kolommen is gekoppeld door ze te converteren naar de binary tekenset:

    ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET binary;
    
  3. koppel aan dergelijke kolommen de codering waarin de gegevens daadwerkelijk werden verzonden door ze om te zetten in de relevante tekenset.

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

Houd er rekening mee dat, als u converteert vanuit een multi-byte-codering, u mogelijk de grootte van de kolom moet vergroten (of zelfs het type ervan moet wijzigen) om de maximaal mogelijke lengte van de geconverteerde tekenreeks aan te passen.

Als men er eenmaal zeker van is dat de kolommen correct zijn gecodeerd, kan men de vergelijking afdwingen met behulp van een Unicode-sortering door ofwel—

  • expliciet converteren van de waarde fos_user.username naar een Unicode-tekenset:

    WHERE CONVERT(fos_user.username USING utf8) = ?
    
  • forceren dat de letterlijke tekenreeks een lagere coërcibility-waarde heeft dan de kolom (zal een impliciete conversie van de waarde van de kolom naar UTF-8 veroorzaken):

    WHERE fos_user.username = ? COLLATE utf8_general_ci
    

Of je kunt, zoals je zegt, de kolom(men) permanent converteren naar een Unicode-codering en de sortering op de juiste manier instellen.

De belangrijkste overweging is dat Unicode-coderingen meer ruimte innemen dan enkelbyte-tekensets, dus:

  • meer opslagruimte kan nodig zijn;

  • vergelijkingen kunnen langzamer zijn; en

  • De lengte van het indexvoorvoegsel moet mogelijk worden aangepast (merk op dat het maximum in bytes is, dus mogelijk minder tekens dan voorheen).

Houd er ook rekening mee dat, zoals gedocumenteerd onder ALTER TABLE Syntaxis :



  1. Hotelkamerprijzen voor verschillende seizoenen

  2. een kolom bijwerken door een waarde af te trekken

  3. Een beperking in SQL Server (T-SQL) laten vallen

  4. Wat is de gemakkelijkste manier om te bepalen of een gebruiker online is? (PHP/MYSQL)