วิธีการเปลี่ยน CHARACTER SET (และ COLLATION) ทั่วฐานข้อมูล


172

โปรแกรมเมอร์ก่อนหน้าของเราตั้งค่าการเรียงที่ไม่ถูกต้องในตาราง (Mysql) เขาตั้งค่าด้วยการเปรียบเทียบภาษาละตินเมื่อควรเป็น UTF8 และตอนนี้ฉันมีปัญหา ทุกระเบียนที่มีตัวอักษรจีนและญี่ปุ่นเปลี่ยนเป็น ??? ตัวละคร

เป็นไปได้ที่จะเปลี่ยนการเรียงหน้าและกลับรายละเอียดของตัวละคร?


ซ้ำซ้อนที่เป็นไปได้ของการแก้ไขตาราง MySql เรียง
kenorb

การเปรียบเทียบจะทำอะไรกับ '???' ชุดตัวอักษร? ฉันคิดว่าจะทำอย่างไรกับชุดตัวละคร?
peterchaula

ฉันกำลังเปลี่ยนชื่อเพื่อแสดงเจตนา การเปลี่ยนการเรียงหน้าเริ่มต้นสำหรับฐานข้อมูลนั้นน้อยกว่าที่ต้องการ
Rick James

คำตอบ:


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
ALTER DATABASE <database_name> CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ciมันจะดีกว่าที่จะทำต่อไปนี้สำหรับการสนับสนุน utf8 เต็ม คุณควรทำเช่นเดียวกันสำหรับอีกสองประโยค
Greeso

คุณจำเป็นต้องใช้ "ALTER TABLE <table_name> MODIFY <column_name> ... " หรือไม่ อ้างอิงจากdev.mysql.com/doc/refman/5.5/en/alter-table.htmlดูเหมือนว่า "เปลี่ยนแปลงตาราง <table_name> แปลงเป็นชุดอักขระ ... " และยังเปลี่ยนคอลัมน์หรือไม่ หรือบางทีฉันไม่ได้อ่าน / ทำความเข้าใจคู่มืออย่างถูกต้อง
hansfn

49

นี่คือวิธีการเปลี่ยนฐานข้อมูล / ตาราง / คอลัมน์ทั้งหมด รันเคียวรีเหล่านี้และพวกเขาจะเอาต์พุตเคียวรีลำดับต่อมาทั้งหมดที่จำเป็นในการแปลงสกีมาทั้งหมดของคุณเป็น utf8 หวังว่านี่จะช่วยได้!

- เปลี่ยน 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';

- เปลี่ยนการเรียงตาราง / ชุดการจัดเรียง

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

ดี. ! ประมาณหนึ่งชั่วโมงที่ฉันพยายามแก้ไขปัญหาเดียวกัน ฉันใช้คำสั่งทั้งสามนี้และฉันเห็นว่าชุดอักขระมีการเปลี่ยนแปลง แต่ปัญหาหลักที่เหลืออยู่สำหรับฉัน ถ้าฉันเขียนโดยตรงไปยังฐานข้อมูลทุกอย่างก็จะปรากฏในเบราว์เซอร์ แต่ถ้าฉันเพิ่มเนื้อหาบางส่วนจากแบบฟอร์มเว็บไซต์ผลลัพธ์ในฐานข้อมูลเป็นเพียง ?????? มีอะไรที่ฉันควรพิจารณาหรือไม่? เว็บแอปของฉันคือแอพ. NET MVC
Tchaps

การบันทึกลงในแบบสอบถามที่มีประโยชน์สำหรับโครงการในอนาคต
Manatax

ฉันแนะนำการแก้ไขบางอย่างเนื่องจากการสืบค้นอัตโนมัติเหล่านี้ยังไม่ปลอดภัยในการใช้ ยังคงมีปัญหากับ CHARACTER_MAXIMUM_LENGTH: ต้นฉบับอาจสูงเกินไปเมื่อคุณเปลี่ยนจากเช่น latin1_swedish_ci เป็น utf8_unicode_ci
Ruben

1
นี่คือคำตอบที่ยอดเยี่ยม ฉันมีความคิดเห็น / คำถามสามข้อ: 1) ทำไมการใช้ "t1" ในรหัส COLUMN ฉันไม่เห็นความต้องการมัน 2) ทำไม "t1.data_type, '(', t1.CHARACTER_MAXIMUM_LENGTH, ')'" และไม่ใช่แค่ "t1.column_type"? 3) ทำไมส่วนผสมของตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก - TABLE_SCHEMA เทียบกับ table_name และอื่น ๆ
hansfn

25

ระวังว่าใน Mysql utf8ชุดอักขระเป็นชุดย่อยของชุดอักขระ UTF8 จริงเท่านั้น เพื่อประหยัดพื้นที่เก็บข้อมูลหนึ่งไบต์ทีม Mysql ตัดสินใจที่จะเก็บอักขระ UTF8 เพียงสามไบต์แทนที่จะเป็นสี่ไบต์เต็ม นั่นหมายความว่าภาษาเอเชียตะวันออกและอิโมจิบางภาษายังไม่ได้รับการสนับสนุน เพื่อให้แน่ใจว่าคุณสามารถเก็บอักขระ UTF8 ทั้งหมดใช้utf8mb4ประเภทข้อมูลและutf8mb4_binหรือutf8mb4_general_ciใน Mysql


1
ถึงตอนนี้ขอแนะนำให้ใช้ utf8mb4_unicode_ciutf8mb4_general_ciแทน ดูstackoverflow.com/questions/766809/…และdrupal.stackexchange.com/questions/166405/…
Robin van Baalen

6

เพิ่มสิ่งที่เดวิด Whittaker โพสต์ฉันได้สร้างแบบสอบถามที่สร้างตารางที่สมบูรณ์และคอลัมน์แก้ไขคำสั่งที่จะแปลงแต่ละตาราง มันอาจเป็นความคิดที่ดีที่จะทำงาน

ชุดเซสชั่น 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 ไม่ได้ผลสำหรับ enums นอกจากนี้ข้อความค้นหาของฉันยังไม่รวมการดูเนื่องจากสิ่งเหล่านี้จะต้องเปลี่ยนแปลงแยกต่างหาก

ฉันเพียงแค่ใช้สคริปต์ Perl เพื่อส่งกลับการเปลี่ยนแปลงทั้งหมดเหล่านี้เป็นอาร์เรย์และทำซ้ำกับพวกเขาแก้ไขคอลัมน์ที่ยาวเกินไป (โดยทั่วไปพวกเขา varchar (256) เมื่อข้อมูลโดยทั่วไปมีเพียง 20 ตัวอักษรในตัวพวกเขาเพื่อให้แก้ไขได้ง่าย )

ฉันพบข้อมูลบางอย่างเสียหายเมื่อทำการเปลี่ยนแปลงจาก latin1 -> utf8mb4 ดูเหมือนว่าจะเป็นอักขระ utf8 ที่เข้ารหัส latin1 ในคอลัมน์จะได้รับการแปลงในการแปลง ฉันเพียงแค่เก็บข้อมูลจากคอลัมน์ที่ฉันรู้ว่าจะเป็นปัญหาในหน่วยความจำจากก่อนและหลังการเปลี่ยนแปลงและเปรียบเทียบพวกเขาและสร้างงบการปรับปรุงเพื่อแก้ไขข้อมูล


4

ที่นี่อธิบายถึงกระบวนการที่ดี อย่างไรก็ตามตัวละครบางตัวที่ไม่พอดีกับอวกาศละตินนั้นหายไปตลอดกาล UTF-8 คือ SUPERSET ของ latin1 ไม่ย้อนกลับ ส่วนใหญ่จะพอดีกับพื้นที่ไบต์เดียว แต่คนที่ไม่ได้กำหนดจะไม่ (ตรวจสอบรายการ latin1 - ไม่ใช่ 256 ตัวอักษรทั้งหมดจะถูกกำหนดขึ้นอยู่กับคำนิยามของ latin1 mysql)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.