Jak zmienić ZESTAW ZNAKÓW (i KOLEKCJĘ) w całej bazie danych?


172

Nasz poprzedni programista ustawił niewłaściwe sortowanie w tabeli (MySQL). Skonfigurował to z łączeniem łacińskim, kiedy powinno to być UTF8, a teraz mam problemy. Każdy rekord ze znakami chińskimi i japońskimi zamienia się w ??? postać.

Czy można zmienić sortowanie i odzyskać szczegóły postaci?



Co ma wspólnego sortowanie z „???” zestaw znaków? Myślałem, że to ma związek z zestawem znaków?
peterchaula

Zmieniam tytuł, aby odzwierciedlić zamiar. Zmiana domyślnego sortowania w bazie danych jest znacznie mniejsza niż oczekiwano.
Rick James

Odpowiedzi:


365

zmień sortowanie w bazie danych:

ALTER DATABASE <database_name> CHARACTER SET utf8 COLLATE utf8mb4_0900_ai_ci;

zmiana sortowania tabeli:

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

zmień sortowanie kolumn:

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

Co utf8mb4_0900_ai_cioznaczają poszczególne częś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

Więcej informacji:


4
Uwaga CHARACTER SET utf8będzie domyślnie, utf8_general_ciale w ALTER DATABASE <database_name> CHARACTER SET utf8 COLLATE utf8_unicode_ci;razie potrzeby możesz również zdefiniować sortowanie w ten sposób
KCD,

1
... i polecam ci to przetestowaćcreate table testit(a varchar(1)); show create table testit \G drop table testit;
KCD,

2
Chcę tylko wspomnieć, że druga zmieni sortowanie na utf8_general_ci; jeśli chcesz go zmienić utf8_unicode_ci, można zdefiniować sortowania: ALTER TABLE <table_name> CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;. Działa to na tabelach dokładnie tak samo, jak na bazach danych, jak wskazał @KCD.
mądrzejszy

9
Aby uzyskać pełną obsługę utf8, lepiej wykonać następujące czynności ALTER DATABASE <database_name> CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci. Powinieneś zrobić to samo dla pozostałych dwóch instrukcji.
Greeso

Czy naprawdę musisz użyć polecenia „ALTER TABLE <nazwa_tabeli> MODIFY <nazwa_kolumny> ...”. Według dev.mysql.com/doc/refman/5.5/en/alter-table.html wydaje się, że "ALTER TABLE <table_name> CONVERT TO CHARACTER SET ..." również zmienia kolumny? A może nie czytam / nie rozumiem poprawnie instrukcji.
hansfn

49

Oto jak zmienić wszystkie bazy danych / tabele / kolumny. Uruchom te zapytania, a wyświetlą wszystkie kolejne zapytania niezbędne do konwersji całego schematu na utf8. Mam nadzieję że to pomoże!

- Zmień domyślne sortowanie bazy danych

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

- Zmień zestawienie tabel / znaków

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';

- Zmień zestawienie COLUMN / 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';

Dobry. ! Próbuję rozwiązać ten sam problem około godziny. Używam tych 3 poleceń i zobaczyłem, że zmienił się zestaw znaków. Ale główny problem pozostaje dla mnie. Jeśli napisałem bezpośrednio do bazy danych, wszystko dobrze się wyświetla w mojej przeglądarce. Ale jeśli dodałem jakąś treść z formularza strony, wynik w bazie to po prostu ??????. Czy jest coś, co powinienem rozważyć? Moja aplikacja internetowa to aplikacja .NET MVC.
Tchaps

Zapisywanie w przydatnych zapytaniach dla przyszłych projektów.
Manatax

Zasugerowałem pewne zmiany, ponieważ te automatyczne zapytania nie były jeszcze bezpieczne w użyciu. Nadal występuje problem z CHARACTER_MAXIMUM_LENGTH: oryginalny może być zbyt wysoki, gdy zmienisz np. Latin1_swedish_ci na utf8_unicode_ci.
Ruben

1
To doskonała odpowiedź. Mam trzy komentarze / pytania: 1) Po co używać „t1” w kodzie COLUMN? Nie widzę takiej potrzeby. 2) Dlaczego „t1.data_type, '(', t1.CHARACTER_MAXIMUM_LENGTH, ')'”, a nie tylko „t1.column_type”? 3) Po co mieszać wielkie i małe litery - TABLE_SCHEMA vs table_name i tak dalej?
hansfn

25

Pamiętaj, że w MySQL utf8zestaw znaków jest tylko podzbiorem prawdziwego zestawu znaków UTF8. Aby zaoszczędzić jeden bajt pamięci, zespół Mysql zdecydował się na przechowywanie tylko trzech bajtów znaków UTF8 zamiast pełnych czterech bajtów. Oznacza to, że niektóre języki wschodnioazjatyckie i emoji nie są w pełni obsługiwane. Aby upewnić się, że możesz przechowywać wszystkie znaki UTF8, użyj utf8mb4typu danych i utf8mb4_binlub utf8mb4_general_ciw MySQL.


1
Obecnie zaleca się używanie utf8mb4_unicode_cizamiast utf8mb4_general_ci. Zobacz stackoverflow.com/questions/766809/… i drupal.stackexchange.com/questions/166405/…
Robin van Baalen

6

Dodając do tego, co napisał David Whittaker, utworzyłem zapytanie, które generuje kompletną instrukcję zmiany tabeli i kolumn, która konwertuje każdą tabelę. Bieganie może być dobrym pomysłem

USTAW SESJĘ group_concat_max_len = 100000;

najpierw upewnij się, że konkat grupowy nie przekracza bardzo małego limitu, jak widać tutaj .

     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;

Różnica między poprzednią odpowiedzią polega na tym, że użycie utf8 zamiast ut8mb4 i użycie t1.data_type z t1.CHARACTER_MAXIMUM_LENGTH nie działa w przypadku wyliczeń. Ponadto moje zapytanie wyklucza widoki, ponieważ będą one musiały zostać zmienione osobno.

Po prostu użyłem skryptu Perla, aby zwrócić wszystkie te zmiany jako tablicę i iterowałem po nich, poprawiłem kolumny, które były zbyt długie (ogólnie były to varchar (256), kiedy dane miały zwykle tylko 20 znaków, więc była to łatwa poprawka ).

Odkryłem, że niektóre dane były uszkodzone podczas zmiany z latin1 -> utf8mb4. Wyglądało na to, że znaki latin1 zakodowane w utf8 w kolumnach zostałyby oszukane podczas konwersji. Po prostu trzymałem dane z kolumn, o których wiedziałem, że będą problemem w pamięci przed i po zmianie, porównałem je i wygenerowałem instrukcje aktualizacji, aby naprawić dane.


4

tutaj dobrze opisuje proces. Jednak niektóre postacie, które nie pasowały do ​​przestrzeni łacińskiej, zniknęły na zawsze. UTF-8 to SUPERSET z latin1. Nie na odwrót. Większość z nich zmieści się w przestrzeni jednobajtowej, ale żadne niezdefiniowane nie (sprawdź listę latin1 - nie wszystkie 256 znaków są zdefiniowane, w zależności od definicji latin1 mysql)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.