从Oracle迁移到PostgreSQL时无效的UTF8字符

时间:2017-06-07 03:00:24

标签: oracle encoding utf-8 data-conversion

我在这里重新提出我的问题。我正在使用AWS DMS工具从Oracle迁移到PostgreSQL。源(oracle)字符集 AL32UTF8 ,目标(Pg)字符集设置为 UT8

所以在源头我有一个数据类型为 varchar2(4000)的列,其中我存储了这样的内容:

This will be my first time visiting Seattle. 

当我尝试迁移时,我收到以下错误:

ERROR: invalid byte sequence for encoding "UTF8": 0xed 0xa0 0xbd

在DMS中有一种方法可以跳过这个,但问题是我必须每次运行DMS并等待它给出无效的字节序列错误,然后通过它。直到现在,我有这么多:

0xed 0xa4 0x88
0xed 0xbd 0x95
0xed 0xa9 0x8e
0xed 0xbc 0xb8
0xed 0xaa 0xbe
0xed 0xba 0xb5
0xed 0xaf 0x83
0xed 0xb5 0xaa
0xed 0xa0 0xbc
0xed 0xbc 0x9f
0xed 0xa0 0xbd
0xed 0xb8 0xa0
0xed 0xbe 0x88
0xed 0xb1 0x8e
0xed 0xb1 0x8e
0xed 0xb1 0x8d
0xed 0xb3 0x99
0xed 0xb1 0x9f
0xed 0xbe 0xa7
0xed 0xb1 0x8c
0xed 0xa0 0xbe
0xed 0xb4 0x96
0xed 0xba 0x80
0xed 0xb4 0xb1
0xed 0xb0 0xa7
0xed 0xbe 0xb8
0xed 0xbe 0xb5
0xed 0xb7 0xbb
0xed 0xb1 0x86
0xed 0xbe 0xb6
0xed 0xbf 0x8a
0xed 0xb0 0xab
0xed 0xb0 0x95
0xed 0xb0 0x94
0xed 0xb0 0x99
0xed 0xb0 0xb1
0xed 0xbf 0x84
0xed 0xba 0x82
0xed 0xb4 0xa8
0xed 0xb0 0xaf
0xed 0xb0 0xb8
0xed 0xb3 0x9e
0xed 0xb4 0xa7
0xed 0xbe 0x81
0xed 0xb1 0x87

从这里的一个论坛帖子中,我得到了以下查询:

 select CASE
            INSTR (
                  RAWTOHEX (
                      utl_raw.cast_to_raw (
                          utl_i18n.raw_to_char (
                                utl_raw.cast_to_raw ( <your_column> )
                              , 'utf8'
                          )
                      )
                  )
                , 'EFBFBD'
            )
        WHEN 0 THEN 'OK'
        ELSE 'FAIL' 
        END
   from <your_table>
      ;

是否可以修改上述查询以提出正则表达式来检查所有这些非法的UTF8编码。

此外,在将 client_encoding 更改为 LATIN1 之后,我能够成功完成迁移,但是我在PG端收到了这个:

This will be my first time visiting Seattle. э НэИ

请查看并发表评论

1 个答案:

答案 0 :(得分:0)

Oracle(或任何其他支持UTF-8的系统)无法存储无效 UTF-8字符,迁移时一定存在问题。请仔细检查有关字符集的每个设置。编码 - 包括您的终端设置和/或编辑器。

Characer U+1F60A SMILING FACE WITH SMILING EYES属于补充多语言平面中的Emoticons块。也许您的迁移工具存在Basic Multilingual Plane之外的字符的一般问题,即U+FFFF以上的字符。

找到它们的一种方法是

SELECT *
FROM ...
WHERE REGEXP_LIKE(<your_column>, UNISTR('[\0001-\FFFF]'));

此条件仅返回Basic Multilingual Plane中的字符。

你也可以尝试这样:

SELECT 
    REGEXP_SUBSTR('This will be my first time visiting Seattle. ', UNISTR('[\FFFF-\DBFF\DFFF]'))
FROM dual;

REGEXP_SUBSTR('THISWILLBEMYFIRSTTIMEVISITINGSEATTLE.',UNISTR('[\FFFF-\DBFF\DFFF]
--------------------------------------------------------------------------------
                                                                                    
1 row selected.

<强>更新

我再次检查了。

  • U+1F60A SMILING FACE WITH SMILING EYES
  • 可以写成UNISTR('\D83D\DE0A')
  • 编码为UTF-8(Oracle字符集AL32UTF8):F0 9F 98 8A
  • 编码为CESU-8(Oracle字符集UTF8):ED A0 BD ED B8 8A

您的错误消息显示:&#34;编码的字节序列无效&#34; UTF8&#34;:0xed 0xa0 0xbd&#34;

ED A0 BD是CESU-8序列。显然,您从Oracle的导出是作为CESU-8 而不是以UTF-8提供的。再次检查您的设置。

更新2

为了从现有数据中替换补充字符,您可以尝试以下方法:

UPDATE FDRGIIT.CS_ACTIONS
SET CS_COMMENTS = REGEXP_REPLACE(CS_COMMENTS, UNISTR('[\FFFF-\DBFF\DFFF]'), UNISTR('\00BF'));

UPDATE FDRGIIT.CS_ACTIONS
SET CS_COMMENTS = REGEXP_REPLACE(CS_COMMENTS, UNISTR('[\FFFF-\DBFF\DFFF]'));

UNISTR('\00BF')是Oracle用于无效字符的占位符(¿)。 UNISTR('\FFFD') - &gt; ()也适合。