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

Encoding issues when spooling files from Oracle Database with UTF-8 encoding

问题描述:

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

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

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

--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*加号无效

我需要它在 SQL*Plus 中工作,但我一直 运行 遇到问题。我尝试了一系列不同的变体。数据库是 Oracle 18c 快捷版:

在 SQL*Plus

上尝试的变体
  1. 只设置char码页为DB对应的utf-8 chcp 65001(utf-8 代码)NLS_LANG 字符集:.WE8MSWIN1252 包含日文字符的表名文件给出 编码“错误”:JAPANESE 包含 3 个字符的文件用于 确定编码工作正常:€;ƒ;‰

  2. 没有更改代码页,但更新了 NLS_LANG 字符集 NLS_LANG charset: .AL32UTF8 表名包含的文件 日语字符现在显示正常:JAPANESE World 带有 3 的文件 然而,用于确定编码的字符现在突然“空”了:;;

  3. 将 NLS_LANG 设置为与 DB 相同并更新代码页 chcp 65001(utf-8 代码)NLS_LANG 字符集:.AL32UTF8 文件带有 包含日文字符的表名现在显示正常: JAPANESE 世 用于确定编码的 3 个字符的文件是 然而现在突然“空”了:;;

  4. 将 NLS_LANG 设置为 NLS_NCHAR_Characterset。以防万一我也 尝试将系统字符集设置为 AL16UTF16,它等于 NLS_NCHAR_Characterset,认为可能有助于解决问题, 但随后我收到以下错误: Error 19 initializing SQL*PLUS 此 OS 环境

    的 NLS 字符集无效

结论/问题

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

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

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

我花了几天时间来隔离这个问题,我很困惑为什么是后者,谁能帮助我?


*Edit,kfinity 提供了解决方案,虽然不能 100% 确定为什么会这样。那么有没有人知道呢?

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

select unistr('AC;92;30') from dual;

sqlplus 从父 cmd window 继承代码 page/encoding。 NLS_LANG 告诉数据库客户端使用了哪个 characterset/encoding。所以,当你 运行

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

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

然后原则上你做对了。不过windowscmd并不完全支持UTF-8,见How to use unicode characters in Windows command line? and/or https://community.oracle.com/tech/developers/discussion/600575/how-to-use-sqlplus-with-utf8-on-windows-command-line

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

另见

我不太确定问题出在哪里,但如果您尝试这样做:

select unistr('AC;92;30') from dual;

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