Bagaimana cara mengubah CHARACTER SET (dan COLLATION) di seluruh basis data?

172

Pemrogram kami sebelumnya mengatur susunan yang salah dalam sebuah tabel (Mysql). Dia mengaturnya dengan susunan Latin, padahal seharusnya UTF8, dan sekarang saya punya masalah. Setiap rekaman dengan karakter Cina dan Jepang beralih ke ??? karakter.

Apakah mungkin untuk mengubah susunan dan mendapatkan kembali detail karakter?

Jeg Bagus
sumber
kemungkinan rangkap dari MySql alter table Collation
kenorb
Apa hubungannya pemeriksaan dengan '???' set karakter? Saya pikir itu ada hubungannya dengan set karakter?
peterchaula
Saya mengubah judul untuk mencerminkan maksud. Mengubah susunan default untuk database jauh lebih sedikit dari yang diinginkan.
Rick James

Jawaban:

365

ubah susunan basis data:

ALTER DATABASE <database_name> CHARACTER SET utf8 COLLATE utf8mb4_0900_ai_ci;

ubah susunan tabel:

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

ubah susunan kolom:

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

Apa arti bagian-bagian utf8mb4_0900_ai_ciitu?

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

Info lebih lanjut:

Timo Huovinen
sumber
4
Waspadai CHARACTER SET utf8akan default utf8_general_citetapi Anda juga dapat menentukan susunan seperti ini ALTER DATABASE <database_name> CHARACTER SET utf8 COLLATE utf8_unicode_ci;jika diperlukan
KCD
1
... dan saya sarankan Anda mengujinyacreate table testit(a varchar(1)); show create table testit \G drop table testit;
KCD
2
Hanya ingin menyebutkan bahwa yang kedua akan mengubah susunan ke utf8_general_ci; jika Anda ingin mengubahnya ke utf8_unicode_ci, Anda dapat menentukan pemeriksaan: ALTER TABLE <table_name> CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;. Ini bekerja pada tabel persis sama dengan bekerja pada database, seperti yang ditunjukkan oleh @KCD.
bijaksana
9
Lebih baik melakukan hal berikut untuk dukungan utf8 penuh ALTER DATABASE <database_name> CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci. Anda harus melakukan hal yang sama untuk dua pernyataan lainnya.
Greeso
Apakah Anda benar-benar perlu menggunakan "ALTER TABLE <table_name> MODIFY <column_name> ...". Menurut dev.mysql.com/doc/refman/5.5/en/alter-table.html tampaknya "ALTER TABLE <table_name> CONVERT KE CHARACTER SET ..." juga mengubah kolom? Atau mungkin saya tidak membaca / memahami manual dengan benar.
hansfn
49

Inilah cara mengubah semua database / tabel / kolom. Jalankan query ini dan mereka akan menampilkan semua pertanyaan selanjutnya yang diperlukan untuk mengonversi seluruh skema Anda menjadi utf8. Semoga ini membantu!

- Ubah DATABASE Default Collation

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

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

- Ubah 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
sumber
Baik. ! Sekitar satu jam saya mencoba menyelesaikan masalah yang sama. Saya menggunakan 3 perintah ini, dan saya melihat bahwa charset telah berubah. Tetapi masalah utama yang tersisa bagi saya. Jika saya menulis langsung ke database maka semuanya tampil dengan baik di browser saya. Tetapi jika saya menambahkan beberapa konten dari formulir situs web, hasil dalam database hanya ??????. Apakah ada sesuatu yang harus saya pertimbangkan? Aplikasi web saya adalah aplikasi .NET MVC.
Tchaps
Menyimpan ke dalam pertanyaan yang berguna untuk proyek masa depan.
Manatax
Saya telah menyarankan beberapa pengeditan karena permintaan otomatis ini belum cukup aman untuk digunakan. Masih ada masalah dengan CHARACTER_MAXIMUM_LENGTH: Yang asli bisa terlalu tinggi ketika Anda mengubah dari mis latin1_swedish_ci ke utf8_unicode_ci.
Ruben
1
Ini jawaban yang sangat bagus. Saya punya tiga komentar / pertanyaan: 1) Mengapa menggunakan "t1" dalam kode COLUMN? Saya tidak melihat adanya kebutuhan untuk itu. 2) Mengapa "t1.data_type, '(', t1.CHARACTER_MAXIMUM_LENGTH, ')'" dan bukan hanya "t1.column_type"? 3) Mengapa campuran huruf besar dan kecil - TABLE_SCHEMA vs table_name dan seterusnya?
hansfn
25

Hati-hati dengan Mysql, utf8set karakter hanya sebagian dari set karakter UTF8 yang asli. Untuk menghemat satu byte penyimpanan, tim Mysql memutuskan untuk menyimpan hanya tiga byte dari karakter UTF8 daripada empat-byte penuh. Itu berarti bahwa beberapa bahasa asia timur dan emoji tidak sepenuhnya didukung. Untuk memastikan Anda dapat menyimpan semua karakter UTF8, gunakan utf8mb4tipe data, dan utf8mb4_binatau utf8mb4_general_cidalam Mysql.

bluecollarcoder
sumber
1
Sekarang, itu disarankan untuk menggunakan utf8mb4_unicode_cibukan utf8mb4_general_ci. Lihat stackoverflow.com/questions/766809/… dan drupal.stackexchange.com/questions/166405/…
Robin van Baalen
6

Menambah apa yang diposkan David Whittaker, saya telah membuat kueri yang menghasilkan tabel lengkap dan kolom mengubah pernyataan yang akan mengonversi setiap tabel. Mungkin ide yang bagus untuk dijalankan

SET SESSION group_concat_max_len = 100000;

pertama-tama untuk memastikan bahwa concat grup Anda tidak melewati batas yang sangat kecil seperti yang terlihat di sini .

     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;

Perbedaan di sini antara jawaban sebelumnya adalah menggunakan utf8 bukan ut8mb4 dan menggunakan t1.data_type dengan t1.CHARACTER_MAXIMUM_LENGTH tidak berfungsi untuk enum. Selain itu, kueri saya mengecualikan tampilan karena harus diubah secara terpisah.

Saya hanya menggunakan skrip Perl untuk mengembalikan semua perubahan ini sebagai array dan mengulanginya, memperbaiki kolom yang terlalu panjang (umumnya varchar (256) ketika data umumnya hanya memiliki 20 karakter di dalamnya sehingga mudah diperbaiki ).

Saya menemukan beberapa data rusak ketika mengubah dari latin1 -> utf8mb4. Tampaknya ut1 disandikan karakter latin1 dalam kolom akan melakukan kesalahan dalam konversi. Saya hanya memegang data dari kolom yang saya tahu akan menjadi masalah dalam memori dari sebelum dan sesudah perubahan dan membandingkannya dan menghasilkan laporan pembaruan untuk memperbaiki data.

Jacob Hundley
sumber
4

disini jelaskan prosesnya dengan baik. Namun, beberapa karakter yang tidak cocok dengan ruang latin hilang selamanya. UTF-8 adalah SUPERSET dari latin1. Bukan sebaliknya. Sebagian besar akan muat dalam ruang byte tunggal, tetapi yang tidak terdefinisi tidak akan (periksa daftar latin1 - tidak semua 256 karakter didefinisikan, tergantung pada definisi mysql's latin1)

MJB
sumber