MySQL - Невалиден символен низ utf8mb4 при актуализация

Въпросът ми е почти същият като този, който се намира тук

MySQL - 1300 - Невалиден utf8 символен низ при актуализация

Не беше представено решение и помощта от лицето (създаване на временна таблица) изглежда не помогна. Ето израза select, който използвам:

SELECT
    CONVERT(line_1 USING utf8mb4),
    CONVERT(line_1 USING latin1),
    HEX(line_1)
FROM address
WHERE ((CAST(CONVERT(line_1 USING latin1) AS CHAR)) <> (CAST(line_1 AS CHAR)))
    AND CONVERT(line_1 USING utf8mb4) IS NULL;
+-------------------------------+------------------------------+----------------------------------------------------+
| CONVERT(line_1 USING utf8mb4) | CONVERT(line_1 USING latin1) | hex(line_1)                                        |
+-------------------------------+------------------------------+----------------------------------------------------+
| NULL                          | Högbergsgatan 97             | 48F6676265726773676174616E203937                   |
| NULL                          | Zücherstrasse 161            | 5AFC636865727374726173736520313631                 |
| NULL                          | 2275, Rue de l'Université    | 323237352C20527565206465206C27556E69766572736974E9 |
| NULL                          | Högbergsgatan 97             | 48F6676265726773676174616E203937                   |
+-------------------------------+------------------------------+----------------------------------------------------+

Когато се опитам да изпълня следната команда за актуализиране, получавам:

UPDATE address
SET line_1 = CONVERT(CAST(CONVERT(line_1 USING latin1) AS CHAR) USING utf8mb4)
WHERE (CAST(CONVERT(line_1 USING latin1) AS CHAR) <> CAST(line_1 AS CHAR))
    AND CONVERT(line_1 USING utf8mb4) IS NULL;
ERROR 1300 (HY000): Invalid utf8mb4 character string: 'F66762'

Опитах се да настроя линията по следните начини, всички произвеждайки същата грешка:

SET line_1 = CAST(CONVERT(line_1 USING latin1) AS CHAR)
SET line_1 = CONVERT(line_1 USING latin1)

Разгледах и http://jonisalonen.com/2012/fixing-doubly-utf-8-encoded-text-in-mysql/, за да видя дали може би това е проблем с двойно кодиране, но нито едно от тях не работеше и продължавах да получавам същата грешка в символен низ.

Освен това разгледах https://mathiasbynens.be/notes/mysql-utf8mb4 по ред за помощ при стъпките за преобразуване, но utf8mb4 и utf8 причиняват същите проблеми. (Първо си помислих, че е utf8 нещо, така че преминах на utf8mb4 и когато все още получавах същите проблеми, знаех, че има по-дълбок проблем)

Както виждате, става нещо странно. Разглеждайки моята таблица с адреси за създаване на шоу, мога да проверя дали наборът от знаци е зададен правилно:

SHOW CREATE TABLE address;
| address | CREATE TABLE `address` (
  `addressid` bigint(20) NOT NULL AUTO_INCREMENT,
  `addressuuid` char(32) COLLATE utf8mb4_unicode_ci NOT NULL,
  `line_1` blob,
  PRIMARY KEY (`addressid`)
) ENGINE=InnoDB AUTO_INCREMENT=48970 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='All potential addresses' |

Освен това можете да видите моите символни променливи са правилни в моя случай:

mysql> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8mb4                    |
| character_set_connection | utf8mb4                    |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8mb4                    |
| character_set_server     | utf8mb4                    |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

Как стигнах до тук

Така че може да е полезно да дадете малко основна информация за проблема само в случай, че нещо на заден план е причинило проблема.

Имах база данни, която първоначално беше настроена на latin1, кодираща всичко. След това пуснах следния код:

SET NAMES 'latin1';

/* We must change things to blob and then back again */
ALTER TABLE `address` CHANGE line_1 line_1 BLOB;
ALTER TABLE `address` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `address` CHANGE line_1 line_1 VARCHAR(64);

Причината за преминаване към blob и след това обратно към varchar е нормалната препоръчителна процедура. (www.percona.com/blog/2013/10/16/utf8-data-on-latin1-tables-converting-to-utf8-without-downtime-or-double-encoding/)

Уведомете ме дали това помага и дали има още информация, която може да бъде предоставена. Използвам MySQL 5.6, така че теоретично би трябвало да се справя по-добре с нещата, но кой знае. Тъй като има само 4 реда, бих могъл просто да актуализирам ръчно всеки един, но теоретично има по-голям основен проблем и тъй като всъщност имам още доста колони, през които трябва да премина, би било хубаво да се уверя, че имам функционален начин за да се справя с тези случаи, в случай че получа нещо с доста редове.


person Aram Papazian    schedule 13.02.2015    source източник
comment
Започнете, като направите SELECT HEX(col), col ..., за да можем да видим какво има в полето. каква е целта Смяна на масата? Или просто излиза нещо като Högbergsgatan?   -  person Rick James    schedule 24.02.2015
comment
Добавих шестнадесетичен към таблицата по-горе. Целта е да можете да конвертирате всичко от старото кодиране на знаци в новото. Но всеки метод, който опитвам, изглежда има проблеми с низовете, които не могат да конвертират/невалидни низове.   -  person Aram Papazian    schedule 24.02.2015
comment
Правилно ли сте разбирали това? Имам същия проблем.   -  person Adergaard    schedule 25.04.2015
comment
Така че, за съжаление, нищо не изглеждаше да работи правилно, тъй като някои неща бяха двойно кодирани, други единични, и се превърна в огромна бъркотия. За щастие нашата база данни не беше твърде голяма, така че в крайна сметка трябваше да експортирам нашата DB, след това ръчно актуализирах всички грешни знаци, поправих кодирането на таблиците и след това импортирах отново. Оттогава не съм имал проблеми, но не беше забавно =/   -  person Aram Papazian    schedule 08.05.2015


Отговори (1)


Тъй като line_1 е петно, а не текстово поле, MySQL няма контрол върху "символите" в него и не се интересува дали това е нетекстова информация (като JPG). В примерите, които сте дали, имате текст latin1 в полето (напр. шестнадесетичен F6 за ö). Следователно CONVERT(line_1 USING latin1) работи „добре“.

Не разбирам целта ти. Опитвате ли се да прочетете BLOB като ТЕКСТ? Ако е така, и ако всички не-ascii символи са кодирани latin1, тогава CONVERT е отговорът.

Ако целта ви е нещо друго, тогава нека подходим от там.

Не беше "двойно кодиран", така че никой от тях нямаше да работи.

ALTER TABLE address CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Направете SHOW CREATE TABLE address и проверете НАБОРА ЗНАЦИ на line_1.

person Rick James    schedule 24.02.2015
comment
Така че първоначално полето беше зададено като VARCHAR(64). Целта е да конвертирате DB от latin1 в utf8mb4. Затова зададох имената на latin1, промених полето на blob, преобразувах набора от символи и след това се опитах да конвертирам обратно във varchar(64). Когато се опитах да конвертирам обратно, получих следната грешка: Неправилна стойност на низ: '\xF6gberg...' за колона 'line_1' на ред 7578 - person Aram Papazian; 24.02.2015
comment
2-step-alter-thru-blob се използва, когато байтовете не са съгласни с декларацията. 1-step-ALTER-CONVERT вероятно е това, от което се нуждаете. (Или изглежда това е, от което се нуждаете сега.) И така, мисля, че имате нужда от 3 стъпки от текущия BLOB с latin1 байтове: SET latin1, ALTER към VARCHAR, ALTER CONVERT. - person Rick James; 25.02.2015
comment
Сравнение на поправките: mysql.rjweb.org/doc.php/charcoll#fixes_for_various_cases - person Rick James; 12.06.2020