我有两个不相关的 Oracle 11g 数据库实例。我需要从一个数据库中选择一个 CLOB 类型的值,然后使用 cx_Oracle 通过 python 将其插入到另一个数据库中。
当我朝一个方向尝试时,结果是:
Traceback (most recent call last):
File "<input>", line 1, in <module>
cx_Oracle.DatabaseError: ORA-00942: table or view does not exist
奇怪的是,当朝另一个方向尝试时,结果是:
Traceback (most recent call last):
File "<input>", line 1, in <module>
cx_Oracle.DatabaseError: ORA-00600: internal error code, arguments: [kglslod:subheap], [8], [0x14D9EA270], [], [], [], [], [], [], [], [], []
在同一数据库中选择和插入 CLOB 值没有问题。
我发现我可以使用自定义输出处理程序修复它:
def OutputTypeHandler(cursor, name, defaultType, size, precision, scale):
if defaultType == cx_Oracle.CLOB:
return cursor.var(cx_Oracle.LONG_STRING, arraysize=cursor.arraysize)
和设置
db_connection.outputtypehandler = OutputTypeHandler
所以我想知道这种行为是设计使然还是还有其他原因导致这种情况?
这里有一些测试数据:
创建表并在数据库1中插入一行
create table test_table_1
(
column_1 clob
);
insert into test_table_1 (column_1) values ('test_data_1');
创建表并在数据库2中插入一行
create table test_table_2
(
column_2 clob
);
insert into test_table_2 (column_2) values ('test_data_2');
Python 脚本无法从数据库 1 获取一个结果并将其插入数据库 2
import cx_Oracle
db_1 = cx_Oracle.connect(<user>, <passwd>, <host_db1>)
db_2 = cx_Oracle.connect(<user>, <passwd>, <host_db2>)
cursor_1 = db_1.cursor()
cursor_2 = db_2.cursor()
result = cursor_1.execute("select column_1 from test_table_1")
result1 = result.fetchone()
cursor_2.execute("insert into test_table_2(column_2) values (:val)", val=result1[0])
结果
Traceback (most recent call last):
File "<input>", line 1, in <module>
cx_Oracle.DatabaseError: ORA-00600: Interner Fehlercode, Argumente: [kglslod:subheap], [8], [0x14DF5A0B0], [], [], [], [], [], [], [], [], []
从数据库2中选择并插入数据库1时的结果
Traceback (most recent call last):
File "<input>", line 8, in <module>
cx_Oracle.DatabaseError: ORA-00942: table or view does not exist
有效的Python脚本
import cx_Oracle
def OutputTypeHandler(cursor: cx_Oracle.Cursor, name, defaultType, size, precision, scale):
"""
Convertes CLOB type to string on reading.
"""
if defaultType == cx_Oracle.CLOB:
return cursor.var(cx_Oracle.LONG_STRING, arraysize=cursor.arraysize)
db_1 = cx_Oracle.connect(<user>, <passwd>, <host_db1>)
db_1.outputtypehandler = OutputTypeHandler
db_2 = cx_Oracle.connect(<user>, <passwd>, <host_db2>)
cursor_1 = db_1.cursor()
cursor_2 = db_2.cursor()
result = cursor_1.execute("select column_1 from test_table_1")
result1 = result.fetchone()
cursor_2.execute("insert into test_table_2(column_2) values (:val)", val=result1[0])
db_2.commit()
版本
- cx-Oracle 7.2.0
- oracle_instant_client 18.5(Linux)
- python 3.6.8
最佳答案
您不能简单地将 LOB 值从一个连接传递到另一个连接。它们特定于特定连接。我会考虑针对这种情况提供更好的错误消息
正如您在自己的问题中指出的,第一个解决方案是通过使用输出类型处理程序来使用 STRING 而不是 CLOB。该技术适用于最大 1 GB 的 CLOB 值,但缺点是整个 CLOB 值必须驻留在连续的内存中。
如果由于长度太长而需要流式传输值,则需要使用类似以下的内容:
cursor_1 = db_1.cursor()
cursor_2 = db_2.cursor()
cursor_1.execute("select column_1 from test_table_1")
sourceLob, = cursor_1.fetchone()
lobVar = cursor_2.var(cx_Oracle.CLOB)
cursor_2.execute("insert into test_table_2 (column_2) values (empty_clob()) returning column_2 into :1", [lobVar])
destLob = lobVar.getvalue()
offset = 1
numBytesInChunk = 65536
while True:
data = sourceLob.read(offset, numBytesInChunk)
if data:
destLob.write(data, offset)
if len(data) < numBytesInChunk:
break
offset += len(data)
db_2.commit()
关于python - 将 CLOB 插入从另一个数据库中选择的数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57177429/