Wie ändere ich das CHARACTER SET (und die COLLATION) in einer Datenbank?

172

Unser vorheriger Programmierer hat die falsche Sortierung in einer Tabelle (MySQL) festgelegt. Er hat es mit lateinischer Kollatierung eingerichtet, wenn es UTF8 sein sollte, und jetzt habe ich Probleme. Jede Platte mit chinesischem und japanischem Schriftzeichen dreht sich um ??? Charakter.

Ist es möglich, die Sortierung zu ändern und die Details des Charakters zurückzugewinnen?

Jeg Bagus
quelle
Mögliches Duplikat von MySql alter table Collation
kenorb
Was hat Kollatierung mit '???' zu tun? Zeichensatz? Ich dachte, das hat mit dem Zeichensatz zu tun?
Peterchaula
Ich ändere den Titel, um die Absicht widerzuspiegeln. Das Ändern der Standardkollatierung für eine Datenbank ist viel geringer als gewünscht.
Rick James

Antworten:

365

Datenbankkollatierung ändern:

ALTER DATABASE <database_name> CHARACTER SET utf8 COLLATE utf8mb4_0900_ai_ci;

Tabellensortierung ändern:

ALTER TABLE <table_name> CONVERT TO CHARACTER SET utf8 COLLATE utf8mb4_0900_ai_ci;

Spaltenkollation ändern:

ALTER TABLE <table_name> MODIFY <column_name> VARCHAR(255) CHARACTER SET utf8 COLLATE utf8mb4_0900_ai_ci;

Was bedeuten die Teile von utf8mb4_0900_ai_ci?

3 bytes -- utf8
4 bytes -- utf8mb4 (new)
v4.0 --   _unicode_
v5.20 --  _unicode_520_
v9.0 --   _0900_ (new)
_bin      -- just compare the bits; don't consider case folding, accents, etc
_ci       -- explicitly case insensitive (A=a) and implicitly accent insensitive (a=á)
_ai_ci    -- explicitly case insensitive and accent insensitive
_as (etc) -- accent-sensitive (etc)
_bin         -- simple, fast
_general_ci  -- fails to compare multiple letters; eg ss=ß, somewhat fast
...          -- slower
_0900_       -- (8.0) much faster because of a rewrite

Mehr Info:

Timo Huovinen
quelle
4
Vorsicht CHARACTER SET utf8wird standardmäßig verwendet, utf8_general_ciaber Sie können die Sortierung ALTER DATABASE <database_name> CHARACTER SET utf8 COLLATE utf8_unicode_ci;bei Bedarf auch so definieren
KCD
1
... und ich empfehle Ihnen, es zu testencreate table testit(a varchar(1)); show create table testit \G drop table testit;
KCD
2
Ich möchte nur erwähnen, dass die zweite die Sortierung in ändert utf8_general_ci. Wenn Sie es ändern möchten utf8_unicode_ci, können Sie die Sortierung definieren : ALTER TABLE <table_name> CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;. Dies funktioniert bei Tabellen genauso wie bei Datenbanken, wie @KCD hervorgehoben hat.
weiser
9
Für die vollständige Unterstützung von utf8 ist es besser, Folgendes zu tun ALTER DATABASE <database_name> CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci. Sie sollten dasselbe für die beiden anderen Anweisungen tun.
Greeso
Müssen Sie wirklich "ALTER TABLE <Tabellenname> MODIFY <Spaltenname> ..." verwenden? Laut dev.mysql.com/doc/refman/5.5/en/alter-table.html scheint "ALTER TABLE <Tabellenname> CONVERT TO CHARACTER SET ..." auch die Spalten zu ändern? Oder vielleicht lese / verstehe ich das Handbuch nicht richtig.
Hansfn
49

Hier erfahren Sie, wie Sie alle Datenbanken / Tabellen / Spalten ändern. Führen Sie diese Abfragen aus, und sie geben alle nachfolgenden Abfragen aus, die zum Konvertieren Ihres gesamten Schemas in utf8 erforderlich sind. Hoffe das hilft!

- Ändern Sie die DATABASE-Standardkollatierung

SELECT DISTINCT concat('ALTER DATABASE `', TABLE_SCHEMA, '` CHARACTER SET utf8 COLLATE utf8_unicode_ci;')
from information_schema.tables
where TABLE_SCHEMA like  'database_name';

- Ändern Sie TABLE Collation / Char Set

SELECT concat('ALTER TABLE `', TABLE_SCHEMA, '`.`', table_name, '` CHARACTER SET utf8 COLLATE utf8_unicode_ci;')
from information_schema.tables
where TABLE_SCHEMA like 'database_name';

- Ändern Sie COLUMN Collation / Char Set

SELECT concat('ALTER TABLE `', t1.TABLE_SCHEMA, '`.`', t1.table_name, '` MODIFY `', t1.column_name, '` ', t1.data_type , '(' , t1.CHARACTER_MAXIMUM_LENGTH , ')' , ' CHARACTER SET utf8 COLLATE utf8_unicode_ci;')
from information_schema.columns t1
where t1.TABLE_SCHEMA like 'database_name' and t1.COLLATION_NAME = 'old_charset_name';
David Whittaker
quelle
Gut. ! Es ist ungefähr eine Stunde, in der ich versuche, das gleiche Problem zu lösen. Ich benutze diese 3 Befehle und habe gesehen, dass sich der Zeichensatz geändert hat. Aber das Hauptproblem bleibt für mich. Wenn ich direkt in die Datenbank geschrieben habe, wird in meinem Browser alles gut angezeigt. Aber wenn ich etwas Inhalt aus dem Website-Formular hinzugefügt habe, ist das Ergebnis in der Datenbank nur ??????. Gibt es etwas, das ich beachten sollte? Meine Web-App ist eine .NET MVC-App.
Tchaps
Speichern in nützlichen Abfragen für zukünftige Projekte.
Manatax
Ich habe einige Änderungen vorgeschlagen, da diese automatisierten Abfragen noch nicht sicher zu verwenden waren. Es gibt immer noch ein Problem mit CHARACTER_MAXIMUM_LENGTH: Das Original kann zu hoch sein, wenn Sie von z. B. latin1_swedish_ci zu utf8_unicode_ci wechseln.
Ruben
1
Dies ist eine ausgezeichnete Antwort. Ich habe drei Kommentare / Fragen: 1) Warum die Verwendung von "t1" im COLUMN-Code? Ich sehe keine Notwendigkeit dafür. 2) Warum "t1.data_type, '(', t1.CHARACTER_MAXIMUM_LENGTH, ')'" und nicht nur "t1.column_type"? 3) Warum die Mischung aus Groß- und Kleinbuchstaben - TABLE_SCHEMA vs table_name und so weiter?
Hansfn
25

Beachten Sie, dass in MySQL der utf8Zeichensatz nur eine Teilmenge des realen UTF8-Zeichensatzes ist. Um ein Byte Speicherplatz zu sparen, hat das MySQL-Team beschlossen, nur drei Bytes eines UTF8-Zeichens anstelle der vollen vier Bytes zu speichern. Das bedeutet, dass einige ostasiatische Sprachen und Emoji nicht vollständig unterstützt werden. Verwenden Sie den utf8mb4Datentyp und utf8mb4_binoder utf8mb4_general_ciin MySQL, um sicherzustellen, dass Sie alle UTF8-Zeichen speichern können.

Bluecollarcoder
quelle
1
Inzwischen wird empfohlen, utf8mb4_unicode_cianstelle von zu verwenden utf8mb4_general_ci. Siehe stackoverflow.com/questions/766809/… und drupal.stackexchange.com/questions/166405/…
Robin van Baalen
6

Zusätzlich zu dem, was David Whittaker gepostet hat, habe ich eine Abfrage erstellt, die die vollständige Anweisung zum Ändern von Tabellen und Spalten generiert, mit der jede Tabelle konvertiert wird. Es kann eine gute Idee sein, zu rennen

SET SESSION group_concat_max_len = 100000;

zuerst sicherstellen , dass Ihre Gruppe concat geht nicht über die sehr kleine Grenze gesehen hier .

     SELECT a.table_name, concat('ALTER TABLE ', a.table_schema, '.', a.table_name, ' DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci, ',
        group_concat(distinct(concat(' MODIFY ',  column_name, ' ', column_type, ' CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ', if (is_nullable = 'NO', ' NOT', ''), ' NULL ',
        if (COLUMN_DEFAULT is not null, CONCAT(' DEFAULT \'', COLUMN_DEFAULT, '\''), ''), if (EXTRA != '', CONCAT(' ', EXTRA), '')))), ';') as alter_statement
    FROM information_schema.columns a
    INNER JOIN INFORMATION_SCHEMA.TABLES b ON a.TABLE_CATALOG = b.TABLE_CATALOG
        AND a.TABLE_SCHEMA = b.TABLE_SCHEMA
        AND a.TABLE_NAME = b.TABLE_NAME
        AND b.table_type != 'view'
    WHERE a.table_schema = ? and (collation_name = 'latin1_swedish_ci' or collation_name = 'utf8mb4_general_ci')
    GROUP BY table_name;

Ein Unterschied zwischen der vorherigen Antwort besteht darin, dass utf8 anstelle von ut8mb4 verwendet wurde und t1.data_type mit t1.CHARACTER_MAXIMUM_LENGTH für Aufzählungen nicht funktioniert hat. Außerdem schließt meine Abfrage Ansichten aus, da diese separat geändert werden müssen.

Ich habe einfach ein Perl-Skript verwendet, um alle diese Änderungen als Array zurückzugeben, und sie durchlaufen, die zu langen Spalten korrigiert (im Allgemeinen waren sie varchar (256), wenn die Daten im Allgemeinen nur 20 Zeichen enthielten, so dass dies eine einfache Lösung war ).

Ich habe festgestellt, dass einige Daten beim Ändern von latin1 -> utf8mb4 beschädigt wurden. Es schien, als ob utf8-codierte lateinische Zeichen in Spalten bei der Konvertierung vermasselt würden. Ich habe einfach Daten aus den Spalten gespeichert, von denen ich wusste, dass sie vor und nach der Änderung ein Speicherproblem darstellen würden, und sie verglichen und Aktualisierungsanweisungen generiert, um die Daten zu korrigieren.

Jacob Hundley
quelle
4

Hier wird der Prozess gut beschrieben. Einige der Charaktere, die nicht in den lateinischen Raum passten, sind jedoch für immer verschwunden. UTF-8 ist ein SUPERSET von latin1. Nicht umgekehrt. Die meisten passen in einen Einzelbyte-Raum, undefinierte jedoch nicht (überprüfen Sie eine Liste von latin1 - abhängig von der latin1-Definition von mysql sind nicht alle 256 Zeichen definiert).

MJB
quelle