Как преобразовать все таблицы в базе данных в одно сопоставление?

82

Я получаю ошибку:

Недопустимое сочетание сопоставлений (utf8_general_ci, IMPLICIT) и (utf8_unicode_ci, IMPLICIT) для операции '=' "

Я попытался изменить обе таблицы вручную, utf8_general_ci,IMPLICITно все еще получаю сообщение об ошибке.

Есть ли способ преобразовать все таблицы utf8_general_ci,IMPLICITи покончить с этим?

Lisovaccaro
источник
Нашел (имел несколько хороших ответов): stackoverflow.com/questions/105572/…
Люк Вятт

Ответы:

166

Вам необходимо выполнить оператор 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";

Вы можете скопировать результаты и выполнить их. Я не тестировал синтаксис, но вы сможете разобраться с остальным. Думайте об этом как о небольшом упражнении.

Надеюсь, это поможет!

Намфибия
источник
7
Для тех, кто ищет быстрое идеальное решение, я использовал следующее для работы с именами таблиц, которые являются возможными ключевыми словами и, конечно же, с использованием точек с запятой :) CONCAT("ALTER TABLE `", TABLE_NAME,"` CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;")
Брайан Лейшман
3
Я обернул этот запрос SELECT GROUP_CONCAT(ExecuteTheString SEPARATOR ' ') FROM (....) tтак, чтобы мне было легче захватить все таблицы сразу в phpMyAdmin.
Zane
Это возвращает пустой результат в MySQL. PHPMYAdmin
Майкл,
@Michael все еще работает на меня. Вы меняли параметры, чтобы отразить вашу ситуацию?
Namphibian
@Namphibian nope, я заменяю только схему своей собственной схемой и типом таблицы (InnoDB)
Майкл
63

Лучший вариант также изменить сопоставление столбцов 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"

Дополнительно, если у вас есть данные с ключом forein в столбце, отличном от utf8, перед запуском сценария группы используйте

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 пытается сопоставить значения данных, но если наборы символов несовместимы, может произойти потеря данных. "

РЕДАКТИРОВАТЬ: особенно с перечислением типа столбца, он просто сбой полностью устанавливает перечисления (даже если нет специальных символов) https://bugs.mysql.com/bug.php?id=26731

Флориан ГЕНРИ - Консультации по банкоматам
источник
27

Предложение @ 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";
dGo
источник
3
Я успешно использовал ваш код, спасибо. Я бы порекомендовал добавить / отключить проверку внешнего ключа, а также добавить кавычки вокруг ключей таблицы.
Игорь Скорич
1
Нет необходимости делать столбцы по отдельности, так как ALTER TABLE CONVERT TO CHARACTER SETвсе столбцы автоматически конвертируются
SystemParadox
Работает отлично. В моем случае мне пришлось заключить в кавычки имена таблиц / столбцов, чтобы избежать конфликтов ключевых слов (например Desc, Password..).
deerchao
19

Ниже представлен более точный запрос. Я привожу пример, как преобразовать его в 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"
Панкадж
источник
Хорошо, но мне нужно было поменять его на CONVERT TO CHARACTER SETдля таблиц с данными
user11153
8

Вы можете использовать этот сценарий 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
Лукас Брзак
источник
7

Если вы используете PhpMyAdmin, теперь вы можете:

  1. Выберите базу данных.
  2. Щелкните вкладку «Операции».
  3. В разделе «Сопоставление» выберите нужное сопоставление.
  4. Установите флажок «Изменить параметры сортировки всех таблиц».
  5. Появится новый флажок «Изменить параметры сортировки столбцов всех таблиц».
  6. Установите флажок «Изменить параметры сортировки столбцов всех таблиц».
  7. Щелкните кнопку «Перейти».

Мне нужно было преобразовать более 250 таблиц. Прошло чуть больше 5 минут.

Команда Mindsect
источник
4

Для 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"

Просто измените имя таблицы и все в порядке.

Калибра
источник
@LucaC. вам нужно увеличить лимит group_concat, например:set session group_concat_max_len = @@max_allowed_packet;
Джеймс
3

Это моя версия сценария 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
)
Петр Стастный
источник
3

Получив ответ от @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
источник
1

Если вам нужен скрипт 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 на имя вашей базы данных.

Xdg
источник
1

Следуя 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"
Том Гулд
источник