使用Python从Oracle导入正确编码的数据
抱歉我又问了一个关于字符编码的问题,我知道你们每天都要处理很多这样的事情,但我还是搞不清楚我的问题,所以就问了。
我们正在做的事情是:
- 用Python和
cx_Oracle
从Oracle数据库中获取数据。 - 用Python把数据写入一个文件。
- 用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 个回答
很不幸,我们的文件中出现了这个符号:�,在后面的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中。不过,我确实想知道你是否可以检查输出为二进制格式的数据,以查看这些符号。