【发布时间】:2015-08-27 01:41:10
【问题描述】:
我一直在将一些数据从 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 db 中的所有列和表都设置为 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'
为了转换,我改变了我最初的“查询生成查询”案例语句来转换列
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
仍然没有运气。在谷歌搜索“0xed 0xa0 0xbd”之后,我仍然不聪明,字符集并不是我真正的东西。 我什至将 3 gig csv 文件打开到它提到的行,并且似乎没有任何不合适的地方,用十六进制编辑器查看我看不到那些字节值(编辑:也许我看起来不够努力)所以我开始没有想法了。我是否遗漏了一些非常简单的东西,令人担忧的是,其他一些表是否也可能被更“无声地”损坏了?
Ubuntu 14.04 操作系统上的 MySQL 版本为 5.5.44,Postgres 为 9.4
【问题讨论】:
-
从the table in this answer看来,0xed 0xa0 0xbd 绝对是无效的UTF8。但是如果文件在某处不包含该字节序列,我看不出你怎么会得到这个错误。
-
该序列编码代码点
U+d83d。这是一个结构上有效的序列,但它编码了一个无效字符。 charbase.com/d83d-unicode-invalid-character 。猜测一下,MySQL 的验证比 PostgreSQL 的更宽松,所以 MySQL 允许它,而 PostgreSQL 拒绝它。 -
搜索“unicode eda0bd”——它似乎有效,但未分配:dev.networkerror.org/utf8/…
标签: mysql postgresql utf-8 postgresql-9.4 mysql-5.5