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

JPR*_*man 5 oracle encoding plsql sqlplus utf-8

问题描述:

\n

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

\n

为了确保文件不变,在运行脚本时对数据进行哈希处理,然后在 Web 应用程序中重新计算该哈希值。这可以工作 9/10 次,但有时它会提供不匹配,即使文件是相同的,我将其隔离为编码问题。

\n

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

\n
--Encoding related information\nSPOOL &&file_desc/Encoding.txt\nSELECT ('\xe2\x82\xac'||';'||'\xc6\x92'||';'||'\xe2\x80\xb0') FROM sys.dual;\nSPOOL off\n
Run Code Online (Sandbox Code Playgroud)\n

预期结果

\n

在使用 UTF-8 编码的数据库上,应正确假脱机包含 NONASCII 字符的数据,并且 3 个 NONASCII 字符也应正确假脱机。

\n

实际结果

\n

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

\n

数据库具有以下字符集(从database_properties获得):

\n

NLS_CHARACTESET:AL32UTF8

\n

NLS_NCHAR_CHARACTERSET:AL16UTF16

\n

SQL-Developer 工作

\n

使用 SQL-Developer 时(将编码设置为 UTF8 后)),我没有任何问题。日语和希腊字符都正确显示,并且用于编码的字符也正确显示,从而在稍后重新计算时导致成功的哈希匹配。

\n

SQL*Plus 无法\xe2\x80\x99 工作

\n

我也需要它在 SQL*Plus 中工作,但我\xe2\x80\x99 遇到了问题。我\xe2\x80\x99已经尝试了一系列不同的变体。DB是Oracle 18c Express版本:

\n

在 SQL*Plus 上尝试的变体

\n
    \n
  1. 仅将字符代码页设置为 utf-8,对应于 DB\nchcp 65001(utf-8 的代码) NLS_LANG 字符集:.WE8MSWIN1252\n表名包含日语字符的文件给出\nan 编码 \xe2\x80\x98error\xe2\ x80\x99: JAPANESE\xc2\xbf 用于\n确定编码的 3 个字符的文件运行良好:\xe2\x82\xac;\xc6\x92;\xe2\x80\xb0

    \n
  2. \n
  3. 代码页没有更改,但更新了 NLS_LANG 字符集\nNLS_LANG 字符集:.AL32UTF8 表名包含日语字符的文件现在显示正常:JAPANESE\xe4\xb8\x96 用于确定编码的包含 3\n字符的文件现在是突然 \xe2\x80\x98empty\xe2\x80\x99 然而:;;

    \n
  4. \n
  5. 将 NLS_LANG 设置为与 DB 相同并更新代码页 chcp\n65001(utf-8 的代码) NLS_LANG 字符集:.AL32UTF8 包含日语字符的表名的文件现在显示正常:\nJAPANESE\xe4\xb8\x96 带有的文件用于确定编码的 3 个字符现在突然变为 \xe2\x80\x98empty\xe2\x80\x99 然而:;;

    \n
  6. \n
  7. 将 NLS_LANG 设置为 NLS_NCHAR_Characterset。以防万一,我还\n尝试将系统字符集设置为 AL16UTF16,它等于\nNLS_NCHAR_Characterset,认为这可能有助于解决问题,\n但随后出现以下错误:错误 19 初始化 SQL*PLUS\n无效的 NLS 字符集对于这个操作系统环境

    \n
  8. \n
\n

结论/问题

\n

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

\n

正如所料,当使用 WE8MSWIN1252 时,非 ASCII 字符的假脱机不起作用,因为它不识别这些字符。

\n

然而,当使用 AL32UTF8 时, sys.dual 形式的 3 个非 ASCII 字符的假脱机不再起作用,即使它确实知道这些字符。

\n

我花了几天时间来解决这个问题,我不知道为什么会出现这种情况,有人可以帮助我吗?

\n
\n

*编辑,kfinity 提供了解决方案,尽管不能 100% 确定为什么会出现这种情况。那么如果有人知道吗?

\n

如果我们将 select 语句替换为以下内容,它确实有效:

\n
select unistr('\\20AC;\\0192;\\2030') from dual;\n
Run Code Online (Sandbox Code Playgroud)\n

kfi*_*ity 1

我不太确定问题是什么,但如果您尝试这样做:

select unistr('\20AC;\0192;\2030') from dual;
Run Code Online (Sandbox Code Playgroud)

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