如何在oracle中将原始字节值放入varchar2列?

时间:2013-09-10 01:56:08

标签: java oracle encoding utf-8 turkish

我们有一个旧客户端与旧版服务器应用程序通信。在土耳其,它发送文本为windows-1254。我们存储它并将其发回。

数据库中的一行有一个名称“İ”,这是一个大写字母,顶部有一个点。在windows-1254中,这是一个0xdd字符,在UTF-8中,即0xc4b0。

如果我查看数据库,我会看到:

SQL> select dump(name, 16) from thing where other thing;

DUMP(NAME,16)
--------------------------------------------------------------------------------
Typ=1 Len=2: c3,9d

怪异。正如有人在另一个问题中指出的那样,但是......

Windows-1254中的“İ”字符为0xdd。事实证明,windows-1252中的0xdd是“Ý”字符,在UTF-8中为0xc39d。因此,我们看到了倾销。

我们认为我们想做的是这个,但它显然不起作用:

SQL> update thing set name = UTL_RAW.CAST_TO_VARCHAR2(UTL_RAW.CONVERT(HEXTORAW('dd'), 'CP1254', 'UTF8')) where otherthing;
update thing set name = UTL_RAW.CAST_TO_VARCHAR2(UTL_RAW.CONVERT(HEXTORAW('dd'), 'CP1254', 'UTF8')) where otherthing
                                                        *
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "SYS.UTL_RAW", line 327

咦?

很多文档讨论了UTL_RAW.CONVERT,没有人显示实际使用它的示例。这是为什么?是否有允许的NLS字符集名称列表?我找不到一个。有什么建议?我可以找到java知道的所有编码列表,但我找不到Oracle的这个列表。

我有一个java应用程序,我用它来编写必须由传统软件读取的数据。该应用程序收到UTF-8。我可以成功地将其转换为Windows-1254字节。我可以将这些转换为windows-1252。如果我然后将这些转换为UTF-8,我可以用以下内容将其写入数据库:

SQL> update this set name = UTL_RAW.CAST_TO_VARCHAR2(hextoraw('c39d')) where otherthing;

1 row updated.

SQL> select dump(name, 16) from thing where otherthing;

DUMP(NAME,16)
--------------------------------------------------------------------------------
Typ=1 Len=2: c3,9d

客户端将此行显示为“İ”。但是,你知道,哇。这看起来很荒谬。但如果那是可行的,那可能就是必须发生的事情......

1 个答案:

答案 0 :(得分:4)

根据UTL_RAW,文档中没有解释的是,字符集由3个部分组成; NLS_LANGUAGE,NLS_TERRITORY和characterset本身。要查看有效值列表,您可以查询V$NLS_VALID_VALUES。完整的语言和地区列表也可在the documentation中找到。

这引发了你的第一个问题。根据Oracle Win-1254,不是 CP1254而是TR8MSWIN1254。同样,虽然存在UTF8字符集,但我怀疑您的数据库是使用AL32UTF8设置的。您可以通过查询NLS_DATABASE_PARAMETERS来仔细检查。

所以,如果这是土耳其语,而你在土耳其,我们假设你的语言和领土只是TURKISH_TURKEY

现在将这个字符集添加到字符集中即可返回您想要的内容:

select utl_raw.convert( hextoraw('dd')
                      , 'TURKISH_TURKEY.AL32UTF8'
                      , 'TURKISH_TURKEY.TR8MSWIN1254'
                      ) as raw_char
  from dual;

RAW_CHAR
-----------------------------------------------------

C4B0

正如您已经注意到的,0xc4b0是UTF-8中的İ表示,因此您可以按照预期使用UTL_RAW.CAST_TO_VARCHAR2 1

select utl_raw.cast_to_varchar2(
           utl_raw.convert( hextoraw('dd')
                          , 'TURKISH_TURKEY.AL32UTF8'
                          , 'TURKISH_TURKEY.TR8MSWIN1254'
                            )) as new_char
  from dual;

<子> 1。我没有可以代表这个角色的基于文本的Oracle客户端;遗憾!