¿Cómo convertir todas las tablas en la base de datos a una colación?

82

Obtengo un error:

Mezcla ilegal de colaciones (utf8_general_ci, IMPLICIT) y (utf8_unicode_ci, IMPLICIT) para la operación '=' "

Intenté cambiar ambas tablas manualmente utf8_general_ci,IMPLICITpero sigo recibiendo el error.

¿Hay alguna manera de convertir todas las tablas utf8_general_ci,IMPLICITy terminar con ellas?

lisovaccaro
fuente
Encontré esto (tenía algunas buenas respuestas): stackoverflow.com/questions/105572/…
Luke Wyatt

Respuestas:

166

Necesita ejecutar una instrucción de tabla de modificación para cada tabla. La declaración seguiría este formulario:

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

Ahora, para obtener todas las tablas en la base de datos, necesitaría ejecutar la siguiente consulta:

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

Así que ahora deja que MySQL escriba el código por ti:

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

Puede copiar los resultados y ejecutarlos. No he probado la sintaxis, pero debería poder averiguar el resto. Piense en ello como un pequeño ejercicio.

¡Espero que ayude!

Anfibio
fuente
7
Para alguien que busca una solución rápida y perfecta, utilicé lo siguiente para trabajar con nombres de tablas como posibles palabras clave y, por supuesto, con punto y coma :) CONCAT("ALTER TABLE `", TABLE_NAME,"` CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;")
Brian Leishman
3
Envolví esta consulta con SELECT GROUP_CONCAT(ExecuteTheString SEPARATOR ' ') FROM (....) tPara poder tomar todas las tablas a la vez más fácilmente en phpMyAdmin.
Zane
Esto devuelve un resultado vacío en MySQL PHPMYAdmin
Michael
@Michael todavía trabaja para mí. ¿Cambió los parámetros para reflejar su situación?
Namphibian
@Namphibian no, solo reemplazo el esquema con mi propio esquema y tipo de tabla (InnoDB)
Michael
63

Mejor opción para cambiar también la clasificación de columnas varchar dentro de la tabla también

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"

Además, si tiene datos con la clave forein en la columna que no es utf8 antes de iniciar el script de grupo, use

SET foreign_key_checks = 0;

Significa que SQL global será para 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;

Pero tenga cuidado si de acuerdo con la documentación de mysql http://dev.mysql.com/doc/refman/5.1/en/charset-column.html ,

Si usa ALTER TABLE para convertir una columna de un juego de caracteres a otro, MySQL intenta asignar los valores de los datos, pero si los juegos de caracteres son incompatibles, puede haber pérdida de datos. "

EDITAR: Especialmente con el tipo de columna enum, simplemente se bloquea por completo el conjunto de enumeraciones (incluso si no hay caracteres especiales) https://bugs.mysql.com/bug.php?id=26731

Florian HENRY - Consultoría de cajeros automáticos
fuente
27

La sugerencia de @ Namphibian me ayudó mucho ...
fue un poco más allá y agregó columnas y vistas al guión

simplemente ingrese el nombre de su esquema a continuación y hará el resto

-- 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
fuente
3
Usé tu código con éxito, gracias. Recomendaría agregar habilitar / deshabilitar la verificación de clave externa y también agregar comillas alrededor de las claves de la tabla.
Igor Skoric
1
No es necesario hacer las columnas individualmente ya que ALTER TABLE CONVERT TO CHARACTER SETconvierte automáticamente todas las columnas
SystemParadox
Funciona genial. En mi caso, tuve que citar nombres de tablas / columnas para evitar conflictos de palabras clave (como Desc, Password..) para el éxito.
deerchao
19

A continuación se muestra la consulta más precisa. Estoy dando un ejemplo de cómo convertirlo a 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"
Pankaj
fuente
Bien, pero necesitaba cambiarlo CONVERT TO CHARACTER SETpara tablas con datos
user11153
8

Puede utilizar este script de 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
Lukas Brzak
fuente
7

Si está usando PhpMyAdmin, ahora puede:

  1. Seleccione la base de datos.
  2. Haga clic en la pestaña "Operaciones".
  3. En la sección "Clasificación", seleccione la clasificación deseada.
  4. Haga clic en la casilla de verificación "Cambiar todas las intercalaciones de tablas".
  5. Aparecerá una nueva casilla de verificación "Cambiar todas las intercalaciones de columnas de las tablas".
  6. Haga clic en la casilla de verificación "Cambiar todas las intercalaciones de columnas de las tablas".
  7. Haga clic en el botón "Ir".

Tenía más de 250 tablas para convertir. Le tomó un poco más de 5 minutos.

Equipo Mindsect
fuente
3

Esta es mi versión de un script bash. Toma el nombre de la base de datos como parámetro y convierte todas las tablas en otro juego de caracteres y colación (dado por otros parámetros o valor predeterminado definido en el script).

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

Llevando la respuesta de @Petr Stastny un paso más allá agregando una variable de contraseña. Preferiría si realmente lo tomara como una contraseña normal en lugar de como un argumento, pero funciona para lo que necesito.

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

Para phpMyAdmin descubrí esto:

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"

Simplemente cambie su calendario de tablas y estará bien.

Calibra
fuente
@LucaC. necesita aumentar el límite de group_concat ex:set session group_concat_max_len = @@max_allowed_packet;
James
1

Si desea un script bash para copiar y pegar:

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

Cambie zabbix por el nombre de su base de datos.

Xdg
fuente
1

Después de GH, agregué los parámetros de usuario y host en caso de que necesite hacer esto en un servidor remoto

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