Як змінити НАЗАД ХАРАКТЕРУ (і КОЛЛАЦІЮ) у базі даних?


172

Наш попередній програміст встановив неправильне порівняння в таблиці (Mysql). Він встановив це за допомогою латинського порівняння, коли це повинно бути UTF8, і тепер у мене є проблеми. Кожен запис із китайським та японським символом звертається до ??? характер.

Чи можна змінити зіставлення і повернути деталі персонажа?


можливий дублікат таблиці MySql alter Collation
kenorb

Що стосується порівняння з "???" набір символів? Я думав, що це стосується набору персонажів?
петерчаула

Я змінюю заголовок, щоб відображати наміри. Зміна порівняння за замовчуванням для бази даних набагато менше, ніж хотілося.
Рік Джеймс

Відповіді:


365

змінити зіставлення бази даних:

ALTER DATABASE <database_name> CHARACTER SET utf8 COLLATE utf8mb4_0900_ai_ci;

змінити зіставлення таблиці:

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

зміни зіставлення стовпців:

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

Що означають частини 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

Більше інформації:


4
Остерігайтеся CHARACTER SET utf8за замовчуванням, utf8_general_ciале ви також можете визначити таке зіставлення, як це ALTER DATABASE <database_name> CHARACTER SET utf8 COLLATE utf8_unicode_ci;необхідно,
KCD

1
... і я рекомендую тестувати йогоcreate table testit(a varchar(1)); show create table testit \G drop table testit;
KCD

2
Просто хочу зазначити, що другий змінить порівняння на utf8_general_ci; якщо ви хочете змінити його utf8_unicode_ci, ви можете визначити параметри сортування: ALTER TABLE <table_name> CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;. Це працює на таблицях точно так само, як і в базах даних, як зазначав @KCD.
мудріший

9
Для повної підтримки utf8 краще виконати наступне ALTER DATABASE <database_name> CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci. Ви повинні зробити те ж саме для двох інших тверджень.
Greeso

Чи дійсно вам потрібно використовувати "ALTER TABLE <Таблиця_табло> MODIFY <ім'я стовпця> ...". Відповідно до dev.mysql.com/doc/refman/5.5/en/alter-table.html, здається, "ALTER TABLE <table_name> CONVERT TO CHARACTER SET ..." також змінює стовпці? А може, я не читаю / розумію посібник правильно.
hansfn

49

Ось як змінити всі бази / таблиці / стовпці. Запустіть ці запити, і вони видадуть усі наступні запити, необхідні для перетворення всієї вашої схеми в utf8. Сподіваюся, це допомагає!

- Зміна зіставлення за замовчуванням DATABASE

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

- Змініть набір столів / набір таблиць

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

- Зміна 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';

Добре. ! Це приблизно година, що я намагаюся вирішити ту саму проблему. Я використовую ці 3 команди, і я побачив, що діаграма змінилася. Але головна проблема залишається для мене. Якщо я писав безпосередньо в базу даних, то все добре відображається в моєму браузері. Але якщо я додав якийсь вміст із форми веб-сайту, результат у базі даних - це просто ??????. Чи є щось, що я повинен розглянути? Мій веб-додаток - це .NET MVC-додаток.
Чапс

Збереження корисних запитів для майбутніх проектів.
Манатакс

Я запропонував деякі зміни, оскільки ці автоматичні запити ще не були досить безпечними для використання. Проблема CHARACTER_MAXIMUM_LENGTH все ще існує: оригінальний може бути занадто високим, коли ви переходите, наприклад, з latin1_swedish_ci на utf8_unicode_ci.
Рубен

1
Це відмінна відповідь. У мене є три коментарі / питання: 1) Чому в COLUMN-коді використовується "t1"? Я не бачу потреби в цьому. 2) Чому "t1.data_type", '(', t1.CHARACTER_MAXIMUM_LENGTH, ')' ", а не лише" t1.column_type "? 3) Чому суміш верхнього та нижнього регістру - TABLE_SCHEMA vs table_name тощо?
hansfn

25

Будьте уважні, що в Mysql utf8набір символів є лише підмножиною реального набору символів UTF8. Щоб зберегти один байт пам’яті, команда Mysql вирішила зберегти лише три байти символів UTF8 замість повних чотирьох байтів. Це означає, що деякі східноазіатські мови та смайли не підтримуються повністю. Щоб переконатися, що ви можете зберігати всі символи UTF8, використовуйте utf8mb4тип даних utf8mb4_binабо utf8mb4_general_ciв Mysql.


1
На сьогоднішній день рекомендується використовувати utf8mb4_unicode_ciзамість цього utf8mb4_general_ci. Див stackoverflow.com/questions/766809 / ... і drupal.stackexchange.com/questions/166405 / ...
Робін ван Баал

6

Додаючи до опублікованого Девідом Уіттакером, я створив запит, який генерує повну таблицю та стовпці, що змінюють оператор, який перетворить кожну таблицю. Можливо, добре запуститись

НАЛАШТУЙТЕ СЕСІЮ group_concat_max_len = 100000;

перший , щоб переконатися , що ваша група CONCAT не виходить за дуже невеликий межа , як показано тут .

     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;

Різниця між попередньою відповіддю полягає в тому, що використання utf8 замість ut8mb4 та використання t1.data_type з t1.CHARACTER_MAXIMUM_LENGTH не працювало для перерахунків. Також мій запит виключає представлення даних, оскільки їх доведеться змінювати окремо.

Я просто використав сценарій Perl, щоб повернути всі ці зміни як масив, і переглянув їх, виправляв занадто довгі стовпці (як правило, вони були varchar (256), коли в цілому дані мали лише 20 символів, так що це було легко виправити ).

Я виявив, що деякі дані були пошкоджені при зміні з латинського -> utf8mb4. Здавалося, що закодовані символи latin1 у стовпцях будуть перетворені у конверсії. Я просто тримав дані з стовпців, за якими я знав, що буде проблемою в пам’яті до і після зміни та порівняв їх та створив заяви оновлення для виправлення даних.


4

тут добре описаний процес. Однак деякі персонажі, які не вмістилися в латинському просторі, зникли назавжди. UTF-8 - це СУПЕРСЕТ з латиниці1. Не навпаки. Більшість буде вміщуватися в однобайтовому просторі, але будь-яких невизначених не буде (перевірте список latin1 - не всі 256 символів визначені, залежно від визначення mysql latin1)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.