使用UTF-8编码从Oracle数据库脱机文件时的编码问题



问题描述:

我有一个脚本运行在Oracle数据库(Windows,或Unix操作系统)。它提取数据,然后将其假脱机到。txt文件。

为了确保文件不变,在运行脚本时对数据进行散列,然后在web应用程序中重新计算该散列。这工作9/10次,但有时它提供一个不匹配,即使文件是相同的,我隔离这是一个编码问题。

为了确定文件使用的编码,脚本将3个NONASCII字符写入文件,这些字符在不同的编码方案中进行不同的编码。这些稍后会映射到后端。

--Encoding related information
SPOOL &&file_desc/Encoding.txt
SELECT ('€'||';'||'ƒ'||';'||'‰') FROM sys.dual;
SPOOL off

预期结果在使用UTF-8编码的数据库上,包含NONASCII字符的数据应该被正确地假脱机处理,并且3个NONASCII字符也应该被正确地假脱机处理。

实际结果

当使用。al32utf8系统字符集(与DB相同)时,数据被正确地假脱机,但用于编码的3个字符不是。这使得我无法确定使用了哪种编码方案。

数据库具有以下字符集(来自database_properties):

NLS_CHARACTESET: AL32UTF8

NLS_NCHAR_CHARACTERSET: AL16UTF16

sql开发人员工作使用SQL-Developer(在将编码设置为UTF8之后)时,我没有问题。日文和希腊文字符都正确显示,用于编码的字符也正确显示,在以后重新计算时,导致哈希匹配成功。

SQL*Plus不工作

我需要它的工作在SQL*Plus以及虽然,我一直遇到的问题。我尝试了一系列不同的变化。数据库是Oracle 18c express edition:

SQL*Plus

  1. 将DB对应的字符码页设置为utf-8chcp 65001(代码为utf-8) NLS_LANG字符集:.WE8MSWIN1252表名包含日文字符的文件给出一个编码' error ': JAPANESE¿带有3个字符的文件确定编码是否有效:€;f;‰

  2. 没有更改代码页,但更新了NLS_LANG字符集NLS_LANG charset: .AL32UTF8表名包含现在日文字符显示的很好:japanese .用于确定编码的字符现在突然变为'空',然而:;;

  3. 设置NLS_LANG与DB和更新后的代码页chcp相同65001(编码为utf-8) NLS_LANG字符集:.AL32UTF8包含日文字符的表名现在显示良好:包含3个字符用于确定编码的文件是现在突然'空'然而:;;;

  4. 设置NLS_LANG为nls_nchar_character。以防我也试图将系统字符集设置为AL16UTF16,它等于nls_nchar_character,认为这可能有助于解决问题,但然后我得到以下错误:错误19初始化SQL*PLUS此操作系统环境的无效NLS字符集

结论/问题

代码页并不重要,因为它只涉及到命令窗口的输出。

正如所料,当使用WE8MSWIN1252时,非ascii字符的假脱机不工作,因为它不知道这些字符。

然而,当使用AL32UTF8时,3个非ascii字符的假脱机形成sys。Dual不再工作,即使它知道字符。

我花了几天的时间来隔离这个问题,我不知道为什么后者是这种情况,有人能帮助我吗?


*编辑在美国,kfinity提供了解决方案,尽管目前还不能100%确定为什么会这样。有人知道吗?

如果我们将select语句替换为下面的语句,它可以工作:

select unistr('20AC;192;2030') from dual;

sqlplus继承父cmd窗口的代码页/编码。NLS_LANG告诉数据库客户端使用哪个字符集/编码。所以,当你运行

chcp 65001
set NLS_LANG=.AL32UTF8
sqlplus ....

chcp 1252 (the default)
set NLS_LANG=.WE8MSWIN1252
sqlplus ....

then原则上你做对了。但是,windowscmd不完全支持UTF-8,参见如何在windows命令行中使用unicode字符?和/或https://community.oracle.com/tech/developers/discussion/600575/how-to-use-sqlplus-with-utf8-on-windows-command-line

您可能必须使用sqlplus以外的其他工具来创建文件。

参见OdbcConnection返回中文字符为"?">

我不太确定问题是什么,但如果你试着做:

select unistr('20AC;192;2030') from dual;

我认为这会绕过让SQL*Plus从. SQL文件中读取正确字符值的问题。

如果SELECT没有返回结果,可能会出现Invalid UTF8 encoding错误

最新更新