Как изменить CHARACTER SET (и COLLATION) по всей базе данных?

172

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

Можно ли изменить сопоставление и вернуть детализацию персонажа?

Джег Багус
источник
возможный дубликат таблицы изменения MySql Collation
kenorb
Какое отношение имеет сортировка к "???" набор символов? Я думал, что это связано с набором символов?
Петерчаула
Я меняю название, чтобы отразить намерение. Изменение параметров сортировки по умолчанию для базы данных намного меньше, чем хотелось бы.
Рик Джеймс

Ответы:

366

изменить параметры сортировки базы данных:

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

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

Тимо Хуовинен
источник
5
Остерегайтесь по 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 ...» также меняет столбцы? Или, может быть, я не правильно читаю / не понимаю руководство.
17
49

Вот как изменить все базы данных / таблицы / столбцы. Запустите эти запросы, и они выведут все последующие запросы, необходимые для преобразования всей вашей схемы в utf8. Надеюсь это поможет!

- Изменить сопоставление базы данных по умолчанию

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.
Чапс
Сохранение в полезные запросы для будущих проектов.
Manatax
Я предложил некоторые изменения, потому что эти автоматизированные запросы еще не были достаточно безопасны для использования. Есть еще проблема с CHARACTER_MAXIMUM_LENGTH: оригинальная может быть слишком высокой, когда вы переходите с, например, latin1_swedish_ci на utf8_unicode_ci.
Рубен
1
Это отличный ответ. У меня три комментария / вопроса: 1) Зачем использовать «t1» в COLUMN-коде? Я не вижу в этом необходимости. 2) Почему "t1.data_type, '(', t1.CHARACTER_MAXIMUM_LENGTH, ')'", а не просто "t1.column_type"? 3) Почему смесь верхнего и нижнего регистра - TABLE_SCHEMA против table_name и так далее?
17
25

Помните, что в Mysql utf8набор символов является лишь подмножеством действительного набора символов UTF8. Чтобы сохранить один байт памяти, команда Mysql решила хранить только три байта символов UTF8 вместо полных четырех байтов. Это означает, что некоторые восточноазиатские языки и эмодзи поддерживаются не полностью. Чтобы убедиться, что вы можете сохранить все символы UTF8, используйте utf8mb4тип данных и / utf8mb4_binили utf8mb4_general_ciMysql.

bluecollarcoder
источник
1
К настоящему времени рекомендуется использовать utf8mb4_unicode_ciвместо utf8mb4_general_ci. См stackoverflow.com/questions/766809/... и drupal.stackexchange.com/questions/166405/...
Робин ван Баален
6

Добавляя к тому, что написал Дэвид Уиттакер, я создал запрос, который генерирует полный оператор таблицы и оператора alter для преобразования каждой таблицы. Это может быть хорошей идеей для запуска

SET SESSION 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 символов, так что это было легко исправить). ).

Я обнаружил, что некоторые данные были повреждены при изменении из latin1 -> utf8mb4. Казалось, что кодированные в столбцах utf8 латинские символы 1 в столбцах дурачатся при преобразовании. Я просто держал данные из столбцов, которые, как я знал, будут проблемой в памяти до и после изменения, сравнивал их и генерировал операторы обновления для исправления данных.

Джейкоб Хандли
источник
4

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

MJB
источник