簡體   English   中英

如何將數據庫中的所有表轉換為一個排序規則?

[英]How to convert all tables in database to one collation?

我收到錯誤:

操作 '=' 的排序規則 (utf8_general_ci,IMPLICIT) 和 (utf8_unicode_ci,IMPLICIT) 的非法混合

我嘗試將兩個表手動更改為utf8_general_ci,IMPLICIT但我仍然遇到錯誤。

有沒有辦法將所有表轉換為utf8_general_ci,IMPLICIT並完成它?

您需要為每個表執行alter table語句。 該聲明將遵循以下形式:

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

現在要獲取數據庫中的所有表,您需要執行以下查詢:

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

所以現在讓MySQL為你編寫代碼:

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

您可以復制結果並執行它們。 我沒有測試語法,但你應該能夠弄清楚其余部分。 把它想象成一個小練習。

希望有所幫助!

更好的選項也可以更改表中varchar列的排序規則

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"

另外,如果你在啟動束腳本之前在非utf8列上有forein鍵的數據

SET foreign_key_checks = 0;

這意味着全局SQL將用於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;

但是如果根據mysql文檔http://dev.mysql.com/doc/refman/5.1/en/charset-column.html ,請注意,

如果使用ALTER TABLE將列從一個字符集轉換為另一個字符集,則MySQL會嘗試映射數據值,但如果字符集不兼容,則可能會丟失數據。

編輯:特別是列類型枚舉,它只是崩潰completly枚舉集(即使沒有特殊的字符) https://bugs.mysql.com/bug.php?id=26731

@ Namphibian的建議幫了我很多...
更進一步,並添加了列和視圖到腳本

只需在下面輸入您的架構名稱,它將完成剩下的工作

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

以下是更准確的查詢。 我舉例說明如何將其轉換為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"

如果您使用的是 PhpMyAdmin,您現在可以:

  1. 選擇數據庫。
  2. 單擊“操作”選項卡。
  3. 在“排序規則”部分下,選擇所需的排序規則。
  4. 單擊“更改所有表排序規則”復選框。
  5. 將出現一個新的“更改所有表列排序規則”復選框。
  6. 單擊“更改所有表的列排序規則”復選框。
  7. 單擊“開始”按鈕。

我有超過 250 個表要轉換。 花了5分鍾多一點。

您可以使用此BASH腳本:

#!/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

對於 phpMyAdmin,我想通了:

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"

只需更改您的表架構名稱就可以了。

如果你想要一個復制粘貼bash腳本:

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

將zabbix更改為您的數據庫名稱。

這是我的bash腳本版本。 它將數據庫名稱作為參數,並將所有表轉換為另一個字符集和排序規則(由另一個參數或腳本中定義的默認值給出)。

#!/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
)

通過添加密碼變量,將@Petr Stastny的答案更進一步。 我更喜歡它實際上是像普通密碼而不是作為參數一樣,但它適用於我需要的東西。

#!/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"

從GH開始,我添加了用戶和主機參數,你需要在遠程服務器上執行此操作

    #!/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"

我將使用 MySQL 程序分享我的答案。 您需要運行 3 條 sql 命令。

1.

DROP PROCEDURE IF EXISTS UpdateTable;

2.

DELIMITER $$

CREATE PROCEDURE UpdateTable()
BEGIN

    DECLARE done INT DEFAULT FALSE;
    DECLARE _table_name CHAR(255);
    DECLARE cur CURSOR FOR
            SELECT table_name FROM information_schema.tables
            WHERE table_schema = 'my_db_name' AND table_type = "BASE TABLE";
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    OPEN cur;
    My_loop: LOOP
        FETCH cur INTO _table_name;
        SET @my_table_name = _table_name;

        IF done THEN
          LEAVE My_loop;
        END IF;

        SET FOREIGN_KEY_CHECKS = 0;

        SET @stmt = CONCAT('ALTER TABLE ', @my_table_name, ' CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;'); 
        PREPARE stmt1 FROM @stmt; 
        EXECUTE stmt1; 
        DEALLOCATE PREPARE stmt1;   
        
        SET FOREIGN_KEY_CHECKS = 1;
            
    END LOOP;
    CLOSE cur;

END$$

DELIMITER ;

3.

CALL UpdateTable();

然后再次運行第一個。 如果你不想存儲程序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM