Jak przekonwertować wszystkie tabele w bazie danych na jedno zestawienie?

82

Otrzymuję błąd:

Niedozwolona kombinacja zestawień (utf8_general_ci, IMPLICIT) i (utf8_unicode_ci, IMPLICIT) dla operacji '=' "

Próbowałem ręcznie zmienić obie tabele, utf8_general_ci,IMPLICITale nadal pojawia się błąd.

Czy istnieje sposób, aby przekonwertować wszystkie tabele utf8_general_ci,IMPLICITi skończyć z tym?

lisovaccaro
źródło
Znalazłem to (miał kilka dobrych odpowiedzi): stackoverflow.com/questions/105572/…
Luke Wyatt

Odpowiedzi:

166

Musisz wykonać instrukcję alter table dla każdej tabeli. Oświadczenie miałoby następującą postać:

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

Teraz, aby uzyskać wszystkie tabele w bazie danych, musisz wykonać następujące zapytanie:

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

Więc teraz pozwól MySQL napisać kod za Ciebie:

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

Możesz skopiować wyniki i wykonać je. Nie testowałem składni, ale powinieneś być w stanie rozgryźć resztę. Potraktuj to jako małe ćwiczenie.

Mam nadzieję, że to pomoże!

Namphibian
źródło
7
Dla kogoś, kto szuka szybkiego idealnego rozwiązania, użyłem następujących słów do pracy z nazwami tabel jako możliwymi słowami kluczowymi i oczywiście przy użyciu średników :) CONCAT("ALTER TABLE `", TABLE_NAME,"` CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;")
Brian Leishman
3
Zawinąłem to zapytanie, SELECT GROUP_CONCAT(ExecuteTheString SEPARATOR ' ') FROM (....) taby móc łatwiej pobrać wszystkie tabele naraz w phpMyAdmin.
Zane
To zwróci pusty wynik w MySQL PHPMYAdmin
Michael
@Michael nadal pracuje dla mnie. Czy zmieniłeś parametry, aby odzwierciedlić Twoją sytuację?
Namphibian
@Namphibian nope Zamieniam schemat tylko na mój własny schemat i typ tabeli (InnoDB)
Michael
63

Lepszą opcją jest zmiana również sortowania kolumn varchar w tabeli

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"

Dodatkowo, jeśli masz dane z kluczem forein w kolumnie innej niż utf8 przed uruchomieniem użycia skryptu grupowego

SET foreign_key_checks = 0;

Oznacza to, że globalny SQL będzie dla 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;

Ale uważaj, jeśli zgodnie z dokumentacją mysql http://dev.mysql.com/doc/refman/5.1/en/charset-column.html ,

Jeśli używasz ALTER TABLE do konwersji kolumny z jednego zestawu znaków na inny, MySQL spróbuje zmapować wartości danych, ale jeśli zestawy znaków są niezgodne, może nastąpić utrata danych. "

EDYCJA: Szczególnie w przypadku wyliczenia typu kolumny, po prostu następuje awaria zestawu wyliczeń (nawet jeśli nie ma specjalnych znaków) https://bugs.mysql.com/bug.php?id=26731

Florian HENRY - doradztwo ATM
źródło
27

Sugestia @ Namphibian bardzo mi pomogła ...
poszła jednak trochę dalej i dodała kolumny i widoki do skryptu

po prostu wprowadź poniżej nazwę schematu, a on zajmie się resztą

-- 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
źródło
3
Użyłem twojego kodu do sukcesu, dziękuję. Zalecałbym włączenie / wyłączenie sprawdzania klucza obcego, a także dodanie cudzysłowów wokół kluczy tabeli.
Igor Skoric
1
Nie ma potrzeby wykonywania poszczególnych kolumn, ponieważ ALTER TABLE CONVERT TO CHARACTER SETautomatycznie konwertuje wszystkie kolumny
SystemParadox
Działa świetnie. W moim przypadku musiałem przytoczyć nazwy tabeli / kolumny w celu uniknięcia konfliktów słów kluczowych (takich jak Desc, Password..) do sukcesu.
deerchao
19

Poniżej znajduje się dokładniejsze zapytanie. Podaję przykład, jak przekonwertować go na 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
źródło
Dobrze, ale musiałem zmienić to na CONVERT TO CHARACTER SETdla tabel z danymi
user11153
8

Możesz użyć tego skryptu 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
źródło
7

Jeśli używasz PhpMyAdmin, możesz teraz:

  1. Wybierz bazę danych.
  2. Kliknij kartę „Operacje”.
  3. W sekcji „Sortowanie” wybierz żądane sortowanie.
  4. Kliknij pole wyboru „Zmień zestawienia wszystkich tabel”.
  5. Pojawi się nowe pole wyboru „Zmień sortowanie kolumn wszystkich tabel”.
  6. Kliknij pole wyboru „Zmień sortowanie kolumn wszystkich tabel”.
  7. Kliknij przycisk „Idź”.

Miałem do konwersji ponad 250 tabel. Zajęło to trochę ponad 5 minut.

Zespół Mindsect
źródło
4

W przypadku phpMyAdmin odkryłem to:

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"

Po prostu zmień swoją nazwę tabeli i wszystko w porządku.

Calibra
źródło
@LucaC. musisz zwiększyć limit group_concat np:set session group_concat_max_len = @@max_allowed_packet;
James
3

To jest moja wersja skryptu bash. Pobiera nazwę bazy danych jako parametr i konwertuje wszystkie tabele na inny zestaw znaków i sortowanie (podane przez inne parametry lub wartość domyślną zdefiniowaną w skrypcie).

#!/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
źródło
3

Idąc o krok dalej z odpowiedzią @Petr Stastny, dodając zmienną hasła. Wolałbym, żeby faktycznie przyjęło to jak zwykłe hasło, a nie jako argument, ale działa na to, czego potrzebowałem.

#!/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
źródło
1

Jeśli chcesz skopiować i wkleić skrypt 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

Zmień zabbix na nazwę swojej bazy danych.

Xdg
źródło
1

W następstwie GH dodałem parametry użytkownika i hosta na wypadek, gdybyś musiał to zrobić na zdalnym serwerze

    #!/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
źródło