使用Python从Oracle导入正确编码的数据

2 投票
1 回答
4242 浏览
提问于 2025-04-17 17:29

抱歉我又问了一个关于字符编码的问题,我知道你们每天都要处理很多这样的事情,但我还是搞不清楚我的问题,所以就问了。

我们正在做的事情是:

  1. 用Python和cx_Oracle从Oracle数据库中获取数据。
  2. 用Python把数据写入一个文件。
  3. 用Python和psycopg2把这个文件导入到Postgres数据库中。

以下是一些重要的Oracle设置:

SQL> select * from NLS_DATABASE_PARAMETERS;

PARAMETER                      VALUE
------------------------------ ----------------------------------------
NLS_LANGUAGE                   AMERICAN
NLS_TERRITORY                  AMERICA
NLS_CURRENCY                   $
NLS_ISO_CURRENCY               AMERICA
NLS_NUMERIC_CHARACTERS         .,
NLS_CHARACTERSET               US7ASCII

根据这个NLS_LANG常见问题,你需要根据你的客户端操作系统来设置NLS_LANG。

运行locale命令得到的结果是:LANG=en_US.UTF-8(其他字段也是en_US.UTF-8)。

所以,在我们的Python脚本中,我们这样设置:

os.environ["NLS_LANG"] = "AMERICAN_AMERICA.AL32UTF8"

然后我们导入数据并写入文件。

row = cur.fetchall()
fil.write(row[0][0]) #For this test, I am only writing one row and one field.

我们把这个文件导入到我们的UTF-8 Postgres数据库中。

不幸的是,出于某种原因,我们在文件和后面的PG表中都看到了这个符号:�。如果我没理解错的话,这个是替换字符。我认为这个字符是用来表示Unicode无法识别某个符号时的。

(在某些文本编辑器中,这个符号显示为�。)

我不明白的是,为什么会发生这种情况?我以为UTF-8是向下兼容7位ASCII的?

即使我们使用的是区域页面,难道不应该仍然有效吗?因为客户端使用的是美国设置,而Oracle服务器使用的是AMERICAN设置。

我该如何检查数据是否正确导入?如果不正确,我该如何修复,以便将来的导入能够正常工作?

注意:Oracle字段是CHAR字段,而不是NCHAR字段。

注意2:我们使用的是Python 2.4,所以没有Python 3.X中的原生Unicode支持。因此,可能是Python在某个地方出错了,尽管我认为cx_Oracle已经处理好了这一切。

谢谢你的时间,祝你有美好的一天。

1 个回答

-1

很不幸,我们的文件中出现了这个符号:�,在后面的PG表中也有。如果我理解得没错,这个是替换字符。我认为这个字符是用来表示如果Unicode无法识别某个符号时就会显示这个字符。

大体上说得对,但还不完全。PostgreSQL在使用UTF-8编码时,会拒绝插入非UTF-8文本字符(你可以在StackOverflow上搜索“Invalid UTF8 postgresql”)。你看到的这个字符,很可能是一个有效的UTF-8字符,但你的字体无法识别它,所以显示成了替换字符。如果这个符号在你的Oracle数据库中确实是替换符号,那你想用什么来替换它呢?如果是这样的话,信息已经丢失了。

我不明白的是,为什么会发生这种情况?我以为UTF-8是向后兼容7位ASCII的?

确实是这样。

我该如何检查数据是否正确导入,如果不正确,我该如何修复,以确保未来的导入是正确的?

你遇到的问题很可能是在Oracle数据库之前的环节。我建议你找出到底是什么在往Oracle数据库中插入问题数据,然后在那里修复。如果你能把Pg中的数据和Oracle中的数据进行对比,就能判断数据是否一字不差(并标记出任何差异)。这就是检查你当前导入的方法。

注意2:我们使用的是Python 2.4,所以没有Python 3.X中的原生Unicode支持。因此,Python可能在某些地方出错,尽管我认为cx_Oracle已经处理好了所有问题。

这也是一种可能性。就我个人而言,对于文件转换,我更喜欢使用Perl,因为它集成了正则表达式,并且对PostgreSQL的支持非常好。不过我知道你的导入程序可能在这个时候不容易转换。我对在Perl中解决UTF-8转换问题更熟悉,而不是在Python中。不过,我确实想知道你是否可以检查输出为二进制格式的数据,以查看这些符号。

撰写回答