Mysql 用于编码的字节序列无效";UTF8";:0xed 0xa0 0xbd

Mysql 用于编码的字节序列无效";UTF8";:0xed 0xa0 0xbd,mysql,postgresql,utf-8,postgresql-9.4,mysql-5.5,Mysql,Postgresql,Utf 8,Postgresql 9.4,Mysql 5.5,我一直在将一些数据从MySQL导入Postgres,计划应该很简单——手动用它们的等效数据类型重新创建表,划分一种输出为CSV的方式,传输数据,将其复制到Postgres。完成了 mysql -u whatever -p whatever -d the_database SELECT * INTO OUTFILE '/tmp/the_table.csv' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\' FR

我一直在将一些数据从MySQL导入Postgres,计划应该很简单——手动用它们的等效数据类型重新创建表,划分一种输出为CSV的方式,传输数据,将其复制到Postgres。完成了

mysql -u whatever -p whatever -d the_database

SELECT * INTO OUTFILE '/tmp/the_table.csv' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\' FROM the_table;
发送并导入到postgres

psql -etcetc -d other_database

COPY the_table FROM '/csv/file/location/the_table.csv' WITH( FORMAT CSV, DELIMITER ',', QUOTE '"', ESCAPE '\', NULL '\N' );
时间太长了,我忘记了“0000-00-00”是一件事。。。 因此,首先,我必须想出一些解决奇怪数据类型的方法,最好是在MySQL端,因此为我计划导入的20多个表编写了这个脚本,以解决任何不兼容问题,并相应地列出列

with a as (
    select
        'the_table'::text as tblname,
        'public'::text as schname
), b as (
    select array_to_string( array_agg( x.column_name ), ',' ) as the_cols from (
        select
            case
                when udt_name = 'timestamp'
                then 'NULLIF('|| column_name::text || ',''0000-00-00 00:00:00'')'
                when udt_name = 'date'
                then 'NULLIF('|| column_name::text || ',''0000-00-00'')'
                else column_name::text
            end as column_name
        from information_schema.columns, a
        where table_schema = a.schname
        and table_name = a.tblname
        order by ordinal_position
    ) x
)
select 'SELECT '|| b.the_cols ||' INTO OUTFILE ''/tmp/'|| a.tblname ||'.csv'' FIELDS TERMINATED BY '','' OPTIONALLY ENCLOSED BY ''"'' ESCAPED BY ''\\'' FROM '|| a.tblname ||';' from a,b;
生成CSV,好的。转过去,好的-转过去一次

BEGIN;
ALTER TABLE the_table SET( autovacuum_enabled = false, toast.autovacuum_enabled = false );
COPY the_table FROM '/csv/file/location/the_table.csv' WITH( FORMAT CSV, DELIMITER ',', QUOTE '"', ESCAPE '\', NULL '\N' ); -- '
ALTER TABLE the_table SET( autovacuum_enabled = true, toast.autovacuum_enabled = true );
COMMIT;
一切都很顺利,直到我发现了这个信息:

ERROR:  invalid byte sequence for encoding "UTF8": 0xed 0xa0 0xbd
CONTEXT:  COPY new_table, line 12345678
第二个表也遇到了相同的错误,但是每成功导入一个表。 现在MySQL数据库中的所有列和表都设置为utf8,第一个包含消息的表是

CREATE TABLE whatever(
col1 int(11) NOT NULL AUTO_INCREMENT,
col2 date,
col3 int(11),
col4 int(11),
col5 int(11),
col6 int(11),
col7 varchar(64),
PRIMARY KEY(col1)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
所以推测数据应该是utf。。。正当为了确保没有重大错误,我编辑了my.cnf,以确保我能想到的一切都包括编码

[character sets]
default-character-set=utf8
default-character-set=utf8
character-set-server = utf8
collation-server = utf8_unicode_ci
init-connect='SET NAMES utf8'
为了转换,我修改了我最初的“querygeneratingquery”case语句来转换列

        case
            when udt_name = 'timestamp'
            then 'NULLIF('|| column_name::text || ',''0000-00-00 00:00:00'')'
            when udt_name = 'date'
            then 'NULLIF('|| column_name::text || ',''0000-00-00'')'
            when udt_name = 'text'
            then 'CONVERT('|| column_name::text || ' USING utf8)'
            else column_name::text
        end as column_name
还是没有运气。在谷歌搜索“0xed0xa0xbd”之后,我仍然一点也不聪明,字符集并不是我真正喜欢的东西。 我甚至打开了3Gig的csv文件到它提到的那一行,似乎没有任何不合适的地方,用十六进制编辑器看,我看不到那些字节值(编辑:也许我看得不够仔细),所以我开始没有主意了。我是否遗漏了一些非常简单且令人担忧的内容,是否有可能其他一些表也被“无声地”损坏了


MySQL版本在ubuntu 14.04操作系统上为5.5.44,Postgres版本为9.4,无需任何进一步的尝试。我选择了最简单的解决方案,只需修改文件即可

iconv -f utf-8 -t utf-8 -c the_file.csv > the_file_iconv.csv

新文件和原始文件之间大约有100个字节,所以其中一定有我看不到的无效字节,它们“正确”导入,所以我认为这是好的,但是,在导入时发现文件之前,如果知道在创建文件时是否有某种方法来强制执行正确的编码,那就太好了。

从外观上看,0xed 0xa0 0xbd肯定是无效的UTF8。但是,如果文件中不包含该字节序列,我看不出您是如何得到这个错误的。该序列对代码点
U+d83d
进行编码。这是一个结构有效的序列,但它编码了一个无效字符。据猜测,MySQL的验证比PostgreSQL的更松散,因此MySQL允许验证,而PostgreSQL拒绝验证。搜索“unicode eda0bd”--它似乎有效,但未分配: