我们有一个旧客户端与旧版服务器应用程序通信。在土耳其,它发送文本为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
客户端将此行显示为“İ”。但是,你知道,哇。这看起来很荒谬。但如果那是可行的,那可能就是必须发生的事情......
答案 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客户端;遗憾!子>