Làm thế nào để chuyển đổi tất cả các bảng trong cơ sở dữ liệu thành một đối chiếu?


82

Tôi gặp lỗi:

Kết hợp bất hợp pháp các đối chiếu (utf8_general_ci, IMPLICIT) và (utf8_unicode_ci, IMPLICIT) cho hoạt động '=' "

Tôi đã thử thay đổi cả hai bảng theo cách thủ công thành utf8_general_ci,IMPLICITnhưng vẫn gặp lỗi.

Có cách nào để chuyển đổi tất cả các bảng thành utf8_general_ci,IMPLICITvà được thực hiện với nó không?


Các mặt hàng này (đã có một số câu trả lời tốt): stackoverflow.com/questions/105572/...
Luke Wyatt

Câu trả lời:


166

Bạn cần thực hiện một câu lệnh bảng thay thế cho mỗi bảng. Tuyên bố sẽ theo mẫu sau:

ALTER TABLE tbl_name
[[DEFAULT] CHARACTER SET charset_name]
[COLLATE collation_name]

Bây giờ để lấy tất cả các bảng trong cơ sở dữ liệu, bạn cần thực hiện truy vấn sau:

SELECT * 
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA="YourDataBaseName"
AND TABLE_TYPE="BASE TABLE";

Vì vậy, bây giờ hãy để MySQL viết mã cho bạn:

SELECT CONCAT("ALTER TABLE ", TABLE_SCHEMA, '.', TABLE_NAME," COLLATE your_collation_name_here;") AS    ExecuteTheString
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA="YourDatabaseName"
AND TABLE_TYPE="BASE TABLE";

Bạn có thể sao chép kết quả và thực thi chúng. Tôi chưa kiểm tra cú pháp nhưng bạn có thể tìm ra phần còn lại. Hãy coi nó như một bài tập nhỏ.

Hy vọng điều đó giúp ích!


7
Đối với một người nào đó tìm kiếm một giải pháp hoàn hảo nhanh chóng, tôi đã sử dụng sau đây để làm việc với các tên bảng là từ khóa có thể và tất nhiên là sử dụng dấu chấm phẩy :) CONCAT("ALTER TABLE `", TABLE_NAME,"` CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;")
Brian Leishman

3
Tôi đã kết hợp truy vấn này với SELECT GROUP_CONCAT(ExecuteTheString SEPARATOR ' ') FROM (....) tĐể tôi có thể lấy tất cả các bảng cùng một lúc dễ dàng hơn trong phpMyAdmin.
Zane

Điều này trả về một kết quả trống trong MySQL PHPMYAdmin
Michael

@Michael vẫn làm việc cho tôi. Bạn có thay đổi các thông số để phản ánh tình hình của bạn không?
Namphibian

@Namphibian Nope tôi chỉ thay thế các schema với riêng lược đồ và bảng kiểu của tôi (InnoDB)
Michael

63

Tùy chọn tốt hơn để thay đổi đối chiếu các cột varchar bên trong bảng cũng

SELECT CONCAT('ALTER TABLE `', TABLE_NAME,'` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;') AS    mySQL
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA= "myschema"
AND TABLE_TYPE="BASE TABLE"

Additionnaly nếu bạn có dữ liệu với khóa ngoại lai trên cột không phải utf8 trước khi khởi chạy sử dụng tập lệnh nhóm

SET foreign_key_checks = 0;

Nó có nghĩa là SQL toàn cầu sẽ dành cho mySQL:

SET foreign_key_checks = 0;
ALTER TABLE `table1` CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;
ALTER TABLE `table2` CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;
ALTER TABLE `tableXXX` CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;
SET foreign_key_checks = 1;

Nhưng hãy cẩn thận nếu theo tài liệu mysql http://dev.mysql.com/doc/refman/5.1/en/charset-column.html ,

Nếu bạn sử dụng ALTER TABLE để chuyển đổi một cột từ bộ ký tự này sang bộ ký tự khác, MySQL sẽ cố gắng ánh xạ các giá trị dữ liệu, nhưng nếu các bộ ký tự không tương thích, có thể bị mất dữ liệu. "

CHỈNH SỬA: Đặc biệt với kiểu cột enum, nó chỉ sụp đổ hoàn toàn bộ enum (ngay cả khi không có ký tự đặc biệt) https://bugs.mysql.com/bug.php?id=26731


27

Đề xuất của @ Namphibian đã giúp tôi rất nhiều ...
mặc dù vậy, đã đi xa hơn một chút và thêm các cột và chế độ xem vào tập lệnh

chỉ cần nhập tên giản đồ của bạn bên dưới và nó sẽ thực hiện phần còn lại

-- set your table name here
SET @MY_SCHEMA = "";

-- tables
SELECT DISTINCT
    CONCAT("ALTER TABLE ", TABLE_NAME," CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") as queries
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA=@MY_SCHEMA
  AND TABLE_TYPE="BASE TABLE"

UNION

-- table columns
SELECT DISTINCT
    CONCAT("ALTER TABLE ", C.TABLE_NAME, " CHANGE ", C.COLUMN_NAME, " ", C.COLUMN_NAME, " ", C.COLUMN_TYPE, " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") as queries
FROM INFORMATION_SCHEMA.COLUMNS as C
    LEFT JOIN INFORMATION_SCHEMA.TABLES as T
        ON C.TABLE_NAME = T.TABLE_NAME
WHERE C.COLLATION_NAME is not null
    AND C.TABLE_SCHEMA=@MY_SCHEMA
    AND T.TABLE_TYPE="BASE TABLE"

UNION

-- views
SELECT DISTINCT
    CONCAT("CREATE OR REPLACE VIEW ", V.TABLE_NAME, " AS ", V.VIEW_DEFINITION, ";") as queries
FROM INFORMATION_SCHEMA.VIEWS as V
    LEFT JOIN INFORMATION_SCHEMA.TABLES as T
        ON V.TABLE_NAME = T.TABLE_NAME
WHERE V.TABLE_SCHEMA=@MY_SCHEMA
    AND T.TABLE_TYPE="VIEW";

3
Tôi đã sử dụng mã của bạn để thành công, cảm ơn bạn. Tôi khuyên bạn nên thêm bật / tắt kiểm tra khóa ngoại và cũng thêm dấu ngoặc kép xung quanh các khóa bảng.
Igor Skoric

1
Nó không phải là cần thiết để làm các cột riêng là ALTER TABLE CONVERT TO CHARACTER SETtự động chuyển đổi tất cả các cột
SystemParadox

Hoạt động tuyệt vời. Trong trường hợp của tôi, tôi phải trích dẫn tên bảng / cột để tránh xung đột từ khóa (chẳng hạn như Desc, Password..) để thành công.
Naichao

19

Dưới đây là truy vấn chính xác hơn. Tôi đang đưa ra ví dụ về cách chuyển đổi nó thành utf8

SELECT CONCAT("ALTER TABLE `", TABLE_NAME,"` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;") AS    mySQL
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA="myschema"
AND TABLE_TYPE="BASE TABLE"

Tốt, nhưng tôi cần phải thay đổi nó để CONVERT TO CHARACTER SETcho các bảng với dữ liệu
user11153

8

Bạn có thể sử dụng tập lệnh BASH này:

#!/bin/bash

USER="YOUR_DATABASE_USER"
PASSWORD="YOUR_USER_PASSWORD"
DB_NAME="DATABASE_NAME"
CHARACTER_SET="utf8" # your default character set
COLLATE="utf8_general_ci" # your default collation

tables=`mysql -u $USER -p$PASSWORD -e "SELECT tbl.TABLE_NAME FROM information_schema.TABLES tbl WHERE tbl.TABLE_SCHEMA = '$DB_NAME' AND tbl.TABLE_TYPE='BASE TABLE'"`

for tableName in $tables; do
    if [[ "$tableName" != "TABLE_NAME" ]] ; then
        mysql -u $USER -p$PASSWORD -e "ALTER TABLE $DB_NAME.$tableName DEFAULT CHARACTER SET $CHARACTER_SET COLLATE $COLLATE;"
        echo "$tableName - done"
    fi
done

7

Nếu bạn đang sử dụng PhpMyAdmin, bây giờ bạn có thể:

  1. Chọn cơ sở dữ liệu.
  2. Nhấp vào tab "Hoạt động".
  3. Trong phần "Đối chiếu", chọn đối chiếu mong muốn.
  4. Nhấp vào hộp kiểm "Thay đổi tất cả các đối chiếu bảng".
  5. Một hộp kiểm "Thay đổi tất cả các đối chiếu cột trong bảng" sẽ xuất hiện.
  6. Nhấp vào hộp kiểm "Thay đổi đối chiếu cột tất cả các bảng".
  7. Nhấp vào nút "Bắt đầu".

Tôi đã có hơn 250 bảng để chuyển đổi. Nó mất hơn 5 phút một chút.


3

Đây là phiên bản của tôi về một kịch bản bash. Nó lấy tên cơ sở dữ liệu làm tham số và chuyển đổi tất cả các bảng sang một bộ ký tự và đối chiếu khác (được cung cấp bởi một tham số khác hoặc giá trị mặc định được xác định trong tập lệnh).

#!/bin/bash

# mycollate.sh <database> [<charset> <collation>]
# changes MySQL/MariaDB charset and collation for one database - all tables and
# all columns in all tables

DB="$1"
CHARSET="$2"
COLL="$3"

[ -n "$DB" ] || exit 1
[ -n "$CHARSET" ] || CHARSET="utf8mb4"
[ -n "$COLL" ] || COLL="utf8mb4_general_ci"

echo $DB
echo "ALTER DATABASE $DB CHARACTER SET $CHARSET COLLATE $COLL;" | mysql

echo "USE $DB; SHOW TABLES;" | mysql -s | (
    while read TABLE; do
        echo $DB.$TABLE
        echo "ALTER TABLE $TABLE CONVERT TO CHARACTER SET $CHARSET COLLATE $COLL;" | mysql $DB
    done
)

3

Tiếp tục câu trả lời từ @Petr Stastny bằng cách thêm một biến mật khẩu. Tôi muốn nếu nó thực sự lấy nó như một mật khẩu thông thường hơn là một đối số, nhưng nó hoạt động cho những gì tôi cần.

#!/bin/bash

# mycollate.sh <database> <password> [<charset> <collation>]
# changes MySQL/MariaDB charset and collation for one database - all tables and
# all columns in all tables

DB="$1"
PW="$2"
CHARSET="$3"
COLL="$4"

[ -n "$DB" ] || exit 1
[ -n "$PW" ]
[ -n "$CHARSET" ] || CHARSET="utf8mb4"
[ -n "$COLL" ] || COLL="utf8mb4_bin"

PW="--password=""$PW"

echo $DB
echo "ALTER DATABASE $DB CHARACTER SET $CHARSET COLLATE $COLL;" | mysql -u root "$PW"

echo "USE $DB; SHOW TABLES;" | mysql -s "$PW" | (
    while read TABLE; do
        echo $DB.$TABLE
        echo "ALTER TABLE $TABLE CONVERT TO CHARACTER SET $CHARSET COLLATE $COLL;" | mysql "$PW" $DB
    done
)

PW="pleaseEmptyMeNow"

3

Đối với phpMyAdmin, tôi đã tìm ra điều này:

SELECT GROUP_CONCAT("ALTER TABLE ", TABLE_SCHEMA, '.', TABLE_NAME," CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" SEPARATOR ' ') AS    OneSQLString
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA="yourtableschemaname"
AND TABLE_TYPE="BASE TABLE"

Chỉ cần thay đổi tên bảng của bạn và bạn ổn.


@LucaC. bạn cần tăng giới hạn group_concat, ví dụ:set session group_concat_max_len = @@max_allowed_packet;
James

1

Nếu bạn muốn có một script bash copy-paste:

var=$(mysql -e 'SELECT CONCAT("ALTER TABLE ", TABLE_NAME," CONVERT TO CHARACTER SET utf8 COLLATE utf8_czech_ci;") AS execTabs FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA="zabbix" AND TABLE_TYPE="BASE TABLE"' -uroot -p )

var+='ALTER DATABASE zabbix CHARACTER SET utf8 COLLATE utf8_general_ci;'

echo $var | cut -d " " -f2- | mysql -uroot -p zabbix

Thay đổi zabbix thành tên cơ sở dữ liệu của bạn.


1

Tiếp theo từ GH, tôi đã thêm thông số người dùng và máy chủ lưu trữ trong trường hợp bạn cần thực hiện việc này trên máy chủ từ xa

    #!/bin/bash

    # mycollate.sh <database> <user> <password> [<host> <charset> <collation>]
    # changes MySQL/MariaDB charset and collation for one database - all tables and
    # all columns in all tables

    DB="$1"
    USER="$2"
    PW="$3"
    HOST="$4"
    CHARSET="$5"
    COLL="$6"

    [ -n "$DB" ] || exit 1
    [ -n "$USER" ] || exit 1
    [ -n "$PW" ] || exit 1
    [ -n "$HOST" ] || HOST="localhost"
    [ -n "$CHARSET" ] || CHARSET="utf8mb4"
    [ -n "$COLL" ] || COLL="utf8mb4_general_ci"

    PW="--password=""$PW"
    HOST="--host=""$HOST"
    USER="--user=""$USER"

    echo $DB
    echo "ALTER DATABASE $DB CHARACTER SET $CHARSET COLLATE $COLL;" | mysql "$HOST" "$USER" "$PW"

    echo "USE $DB; SHOW TABLES;" | mysql  "$HOST" "$USER" "$PW" | (
        while read TABLE; do
            echo $DB.$TABLE
            echo "ALTER TABLE $TABLE CONVERT TO CHARACTER SET $CHARSET COLLATE $COLL;" | mysql  "$HOST" "$USER" "$PW" $DB
        done
    )

    PW="pleaseEmptyMeNow"
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.