在Oracle SQL Developer中与字符串连接时,String丢失最后一个字符

时间:2013-09-03 13:47:27

标签: sql oracle character-encoding plsql oracle-sqldeveloper

如果我有一个原始字符串并将其转换为varchar2然后将其转换为raw,那么所有原始信息仍然存在。但是,如果我将它转换为varchar2然后将任何内容连接到它(包括一个空字符串),我会丢失最后一个字符。 这是我用来复制它的代码:

SET SERVEROUTPUT ON;
DECLARE
  raw_string RAW(100);
  v_string VARCHAR2(100);
  raw_string2 RAW(100);

BEGIN
    raw_string := 'C5C6C7';
    v_string := utl_raw.cast_to_varchar2(raw_string);

    dbms_output.put_line('Raw string:     ' || utl_raw.cast_to_raw(v_string) );
    v_string := v_string || '';
    dbms_output.put_line('New raw string: ' || utl_raw.cast_to_raw(v_string) );
END; 
/

第11行和第13行之间的唯一区别是第6行是在v_string与空字符串连接之后运行的。但输出是这样的:

Raw string:     C5C6C7
New raw string: C5C6

如果我没有连接任何内容,新的原始字符串将是相同的,但如果我向字符串添加任何内容,即使在它的前面,它也会丢失最后一部分。它只发生在某些字符上。如果我用'61'(小写'a')结束原始,那么什么都不会丢失。

我正在使用Oracle SQl Developer v.3.2.20.09

这让我困惑了一段时间,我不确定我是否遗漏了某些内容,或者这只是一个错误,但任何帮助都会非常感激。

1 个答案:

答案 0 :(得分:5)

当您使用RAWsVARCHARs时,必须向我们提供您正在使用的字符集(数据库字符集和客户端cs)。

原因是每个字节值对于从0x000xFF的原始字节都是合法的。而大多数字符集都有非法值:字节值对应于无字符。

当Oracle遇到这样的价值观时,后果可能无法预测。这很可能发生在这里。

例如,在UTF-8中,byte whose binary representation starts with '110...' is the first byte of a two-byte character

这正是您的情况:以C开头的字节具有以1100开头的二进制表示,并且只能是双字节字符的第一个字节。第二个字节必须以10..(8到B)开头。因此,如果我不得不猜测我会预测你使用的是UTF-8,因为它有很多非法字节值。

我们可以观察到使用非法的UTF-8值会导致许多问题:

SQL> select utl_raw.cast_to_varchar2('C5C6') i0 from dual;

I0
--------------------------------------------------------------------------------
ÅÆ

SQL> select utl_raw.cast_to_varchar2('C5C6')||'' i1 from dual;

I1
--------------------------------------------------------------------------------
Å

SQL> select utl_raw.cast_to_varchar2('C5C6')||''||'' i2 from dual;

I2
--------------------------------------------------------------------------------

事实上,对于任何字符集,盲目地将原始数据转换为varchar2通常是个坏主意。 当您知道这些值是合法的时,您只想转换为varchar2(即raw本身是来自varchar2的转换)。

当您需要使用varchar2表示raw时,要显示或通过文本媒体发送,使用hextoraw或编码(例如base64 UTL_ENCODE更安全})。