Làm cách nào để thay đổi BỘ SẮC BỘ (và THU THẬP) trong toàn bộ cơ sở dữ liệu?


172

Lập trình viên trước của chúng tôi đặt đối chiếu sai trong một bảng (Mysql). Anh ấy đã thiết lập nó với đối chiếu Latin, khi đó phải là UTF8, và bây giờ tôi có vấn đề. Mọi kỷ lục với nhân vật Trung Quốc và Nhật Bản đều chuyển sang ??? tính cách.

Có thể thay đổi đối chiếu và lấy lại chi tiết của nhân vật?


bản sao có thể có của bảng thay đổi MySql Collation
kenorb

Đối chiếu có liên quan gì với '???' bộ ký tự? Tôi nghĩ đó là để làm với bộ nhân vật?
peterchaula

Tôi đang thay đổi tiêu đề để phản ánh ý định. Thay đổi đối chiếu mặc định cho cơ sở dữ liệu ít hơn nhiều so với mong muốn.
Rick James

Câu trả lời:


365

thay đổi đối chiếu cơ sở dữ liệu:

ALTER DATABASE <database_name> CHARACTER SET utf8 COLLATE utf8mb4_0900_ai_ci;

thay đổi bảng đối chiếu:

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

thay đổi đối chiếu cột:

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

Các bộ phận của utf8mb4_0900_ai_ciý nghĩa là gì?

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

Thêm thông tin:


4
Cẩn thận CHARACTER SET utf8sẽ mặc định utf8_general_cinhưng bạn cũng có thể xác định đối chiếu như thế này ALTER DATABASE <database_name> CHARACTER SET utf8 COLLATE utf8_unicode_ci;nếu cần
KCD

1
... và tôi khuyên bạn nên kiểm tra nócreate table testit(a varchar(1)); show create table testit \G drop table testit;
KCD

2
Chỉ muốn đề cập rằng thứ hai sẽ thay đổi đối chiếu thành utf8_general_ci; nếu bạn muốn thay đổi nó thành utf8_unicode_ci, bạn có thể xác định đối chiếu : ALTER TABLE <table_name> CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;. Điều này hoạt động trên các bảng giống hệt như nó hoạt động trên cơ sở dữ liệu, như @KCD đã chỉ ra.
khôn ngoan hơn

9
Tốt hơn là làm như sau để được hỗ trợ đầy đủ utf8 ALTER DATABASE <database_name> CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci. Bạn nên làm tương tự cho hai tuyên bố khác.
Greeso

Bạn có thực sự cần phải sử dụng "ALTER TABLE <table_name> MODIFY <cột_name> ...". Theo dev.mysql.com/doc/refman/5.5/en/alter-table.html có vẻ như "ALTER TABLE <table_name> CHUYỂN ĐỔI TÙY CHỌN ..." cũng thay đổi các cột? Hoặc có thể tôi không đọc / hiểu hướng dẫn sử dụng một cách chính xác.
hansfn

49

Đây là cách thay đổi tất cả các cơ sở dữ liệu / bảng / cột. Chạy các truy vấn này và chúng sẽ xuất tất cả các truy vấn tiếp theo cần thiết để chuyển đổi toàn bộ lược đồ của bạn thành utf8. Hi vọng điêu nay co ich!

- Thay đổi đối chiếu mặc định của 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';

- Thay đổi 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';

- Thay đổi Collation 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';

Tốt ! Đó là khoảng một giờ mà tôi đang cố gắng giải quyết vấn đề tương tự. Tôi sử dụng 3 lệnh này và tôi thấy rằng bộ ký tự đã thay đổi. Nhưng vấn đề chính vẫn là cho tôi. Nếu tôi viết trực tiếp vào cơ sở dữ liệu thì mọi thứ sẽ hiển thị tốt trong trình duyệt của tôi. Nhưng nếu tôi thêm một số nội dung từ mẫu trang web, kết quả trong cơ sở dữ liệu chỉ là ??????. Có bất cứ điều gì tôi nên xem xét? Ứng dụng web của tôi là một ứng dụng .NET MVC.
Tchaps 11/07/2015

Lưu vào các truy vấn hữu ích cho các dự án trong tương lai.
Manatax

Tôi đã đề xuất một số chỉnh sửa vì những truy vấn tự động này chưa an toàn để sử dụng. Vẫn còn một vấn đề với CHARACTER_MAXIMUM_LENGTH: Bản gốc có thể quá cao khi bạn thay đổi từ ví dụ latin1_swbur_ci sang utf8_unicode_ci.
Ruben

1
Đây là một câu trả lời tuyệt vời. Tôi có ba nhận xét / câu hỏi: 1) Tại sao việc sử dụng "t1" trong mã COLUMN? Tôi không thấy bất kỳ nhu cầu nào cho nó. 2) Tại sao "t1.data_type, '(', t1.CHARACTER_MAXIMUM_LENGTH, ')'" chứ không chỉ là "t1.column_type"? 3) Tại sao hỗn hợp chữ hoa và chữ thường - TABLE_SCHema vs tên_bạn và như vậy?
hansfn

25

Coi chừng trong Mysql, bộ utf8ký tự chỉ là một tập hợp con của bộ ký tự UTF8 thực. Để tiết kiệm một byte dung lượng lưu trữ, nhóm Mysql đã quyết định chỉ lưu trữ ba byte của một ký tự UTF8 thay vì bốn byte đầy đủ. Điều đó có nghĩa là một số ngôn ngữ và biểu tượng cảm xúc Đông Á không được hỗ trợ đầy đủ. Để đảm bảo bạn có thể lưu trữ tất cả các ký tự UTF8, hãy sử dụng utf8mb4kiểu dữ liệu và utf8mb4_binhoặc utf8mb4_general_citrong Mysql.


1
Đến bây giờ, nên sử dụng utf8mb4_unicode_cithay vì utf8mb4_general_ci. Xem stackoverflow.com/questions/766809/ trêndrupal.stackexchange.com/questions/166405/iêu
Robin van Baalen

6

Thêm vào những gì David Whittaker đã đăng, tôi đã tạo một truy vấn tạo ra câu lệnh thay đổi bảng và cột hoàn chỉnh sẽ chuyển đổi từng bảng. Nó có thể là một ý tưởng tốt để chạy

THIẾT LẬP nhóm_concat_max_len = 100000;

đầu tiên để đảm bảo concat nhóm của bạn không vượt quá giới hạn rất nhỏ như đã thấy ở đây .

     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;

Một sự khác biệt ở đây giữa câu trả lời trước đó là nó sử dụng utf8 thay vì ut8mb4 và sử dụng t1.data_type với t1.CHARACTER_MAXIMUM_LENGTH không hoạt động cho enums. Ngoài ra, truy vấn của tôi loại trừ các lượt xem vì chúng sẽ phải thay đổi riêng.

Tôi chỉ đơn giản sử dụng tập lệnh Perl để trả về tất cả các thay đổi này dưới dạng một mảng và lặp đi lặp lại trên chúng, đã sửa các cột quá dài (nói chung chúng là varchar (256) khi dữ liệu thường chỉ có 20 ký tự trong đó để dễ khắc phục ).

Tôi tìm thấy một số dữ liệu bị hỏng khi thay đổi từ latin1 -> utf8mb4. Dường như các ký tự latin1 được mã hóa utf8 trong các cột sẽ bị biến đổi trong quá trình chuyển đổi. Tôi chỉ đơn giản giữ dữ liệu từ các cột mà tôi biết sẽ là một vấn đề trong bộ nhớ từ trước và sau khi thay đổi và so sánh chúng và tạo ra các báo cáo cập nhật để sửa dữ liệu.


4

ở đây mô tả quá trình tốt. Tuy nhiên, một số nhân vật không phù hợp với không gian Latin sẽ biến mất vĩnh viễn. UTF-8 là một SUPERSET của latin1. Không phải ngược lại. Hầu hết sẽ phù hợp với không gian byte đơn, nhưng bất kỳ cái nào không xác định sẽ không (kiểm tra danh sách latin1 - không phải tất cả 256 ký tự được xác định, tùy thuộc vào định nghĩa latin1 của mysql)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.