Sql ORA-29275:部分多字节字符

Sql ORA-29275:部分多字节字符,sql,oracle,Sql,Oracle,我输入的数据来自一个平面文件,其中一列有英文、日文和中文字符。 我将这些值加载到模式定义为VARCHAR2(250字符)的临时表列中,主表列的定义为VARCHAR2(250字符),我无法更改。 所以,我在这个专栏上做了一个SUBSTR。当我把桌子装上后 SELECT * FROM TABLE …我得到这个错误: ORA-29275:部分多字节字符 如果选择其他列,则不会出现问题。根据数据库字符集的不同,使用substr的行为会有所不同。根据您的描述,我假设您的DB字符集不是Unicode变体之

我输入的数据来自一个平面文件,其中一列有英文、日文和中文字符。 我将这些值加载到模式定义为VARCHAR2(250字符)的临时表列中,主表列的定义为VARCHAR2(250字符),我无法更改。 所以,我在这个专栏上做了一个SUBSTR。当我把桌子装上后

SELECT * FROM TABLE
…我得到这个错误:

ORA-29275:部分多字节字符


如果选择其他列,则不会出现问题。

根据数据库字符集的不同,使用substr的行为会有所不同。根据您的描述,我假设您的DB字符集不是Unicode变体之一,您必须将varchar2(250字符)数据截断为250字节或更少。这是危险的,因为它可以在2字节字符的中间停止,从而得到所得到的消息。您应该查看substrc()的文档,它将根据字符而不是字节计算其长度


如果您进一步解释为什么需要丢弃部分数据,可能会有所帮助。

当您将数据从
250字符
列复制到
250字节
列时,应该使用
SUBSTRB
。此函数将只输出完整字符(您不会得到不完整的unicode字符):

编辑: 对结果字符串的实际长度以及结果字符串是否包含无效的字节序列进行了有趣的注释。考虑下面的AL32 UTF8 dB:

SQL> select lengthb('ÏÏÏ'),
  2         lengthb(substrb('ÏÏÏÏÏÏ', 1, 5)),
  3         dump('ÏÏÏ'),
  4         dump(substrb('ÏÏÏÏÏÏ', 1, 5))
  5    FROM dual;

LE LE DUMP('ÏÏÏ')                           DUMP(SUBSTRB('ÏÏÏÏÏÏ',1,5))
-- -- ------------------------------------- -------------------------------
 6  5 Typ=96 Len=6: 195,143,195,143,195,143 Typ=1 Len=5: 195,143,195,143,32
正如您所看到的,
substrb
字符串的最后一个字节不是特殊字符的被截断的第一个字节,而是对合法字符进行编码(此字符集中的前128个字符与ASCII7US字符集相同,因此这将对
'
空格字符进行编码,如另一个答案中建议的那样使用RTRIM将删除最后一个字符)

此外,我还使用字符集AL16UTF16得到了这个有趣的结果:

SQL> select lengthb(N'ĈĈ') le,
  2         dump(N'ĈĈ') dump,
  3         lengthb(substrb(N'Ĉ', 1, 3)) length_substr,
  4         dump(substrb(N'ĈĈ', 1, 3)) dump_substr
  5    from dual;

        LE DUMP                    LENGTH_SUBSTR DUMP_SUBSTR
---------- ----------------------- ------------- -----------------
         4 Typ=96 Len=4: 1,8,1,8               2 Typ=1 Len=2: 1,8
在这种情况下,Oracle选择在第二个字节后剪切字符串,因为在AL16UTF16字符集中没有合法的单字节字符。生成的字符串只有2个字节,而不是3个字节


这将需要进一步的测试,并不是一个严格的演示,但我仍然坚持我的第一个直觉,即
substrb
将返回一个有效的字节序列,对一个有效的字符串进行编码。

我想我可能已经找到了一个很好的方法 如果您执行
rtrim(substrb()中华人', 1,8))
您得到的是
'中华'和预期的字节长度为6


请尝试

源系统中的“描述”列允许创建非常长的字符串,并且数据文件是从源系统提取的,但目标系统不允许超过250个字节。中文字符占用超过一个字节,这就造成了问题,我用来加载的ETL工具是informatica,确实如此不支持完整的oracle函数。我将检查substrc()是否是可用的。这不应该是substrc吗?substrb以字节为单位复制并可以截断扩展字符。@Jim:该列必须被截断,一个
250字符
列可能有多达1000字节的数据,它不适合
250字节
列。该函数不会将一个UTF-8字符切成两半。但是:结果是:将始终是合法的UTF-8字符串。@Vincent:它不会将字符一分为二似乎不是真的-如果你在ch8和ch7列周围环绕一个长度,那么我打赌你将分别得到8和7。(无论如何,在11g中)我怀疑,可能是因为他们定义字符编码的巧妙方式,部分字符通常是不可打印的,因此被忽略了……[我有一个模糊的计划,尝试在substrb之后使用(基于字符的)长度(可能也会忽略奇数字节)来正确地修剪奇数字节]然后基于字符的substr扩展到这个长度……但是,这只是一个周末,这个问题将在它的两周年纪念日到来!]@mwardm:这很有趣,我没有想到输出可能是一个无效的字节字符串(因为它是varchar2)但是可以正确显示。我现在没有访问数据库的权限,但我会在有权限的时候看一看(可能不是这个周末:)谢谢Taryn。它帮助我解决了这个问题。SourceDB-UTF8目标DB-AL32UTF8收到错误:ORA-29275:部分多字节字符
SQL> select lengthb(N'ĈĈ') le,
  2         dump(N'ĈĈ') dump,
  3         lengthb(substrb(N'Ĉ', 1, 3)) length_substr,
  4         dump(substrb(N'ĈĈ', 1, 3)) dump_substr
  5    from dual;

        LE DUMP                    LENGTH_SUBSTR DUMP_SUBSTR
---------- ----------------------- ------------- -----------------
         4 Typ=96 Len=4: 1,8,1,8               2 Typ=1 Len=2: 1,8